mirror of
https://github.com/topjohnwu/cxx.git
synced 2024-10-07 09:03:30 +00:00
Parse discriminant values from clang AST
This commit is contained in:
parent
ad7a3bdc48
commit
e2250bca87
@ -1,13 +1,14 @@
|
||||
use crate::syntax::attrs::OtherAttrs;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::{Api, Doc, Enum, ForeignName, Pair, Variant};
|
||||
use crate::syntax::{Api, Discriminant, Doc, Enum, ForeignName, Pair, Variant};
|
||||
use proc_macro2::Ident;
|
||||
use quote::format_ident;
|
||||
use serde::Deserialize;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
const CXX_CLANG_AST: &str = "CXX_CLANG_AST";
|
||||
|
||||
@ -18,6 +19,8 @@ enum Clang {
|
||||
NamespaceDecl(NamespaceDecl),
|
||||
EnumDecl(EnumDecl),
|
||||
EnumConstantDecl(EnumConstantDecl),
|
||||
ImplicitCastExpr,
|
||||
ConstantExpr(ConstantExpr),
|
||||
Unknown,
|
||||
}
|
||||
|
||||
@ -36,6 +39,11 @@ struct EnumConstantDecl {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ConstantExpr {
|
||||
value: String,
|
||||
}
|
||||
|
||||
pub fn load(cx: &mut Errors, apis: &mut [Api]) {
|
||||
let ref mut variants_from_header = Vec::new();
|
||||
for api in apis {
|
||||
@ -151,6 +159,32 @@ fn traverse<'a>(
|
||||
Ok(ident) => ident,
|
||||
Err(_) => format_ident!("__Variant{}", enm.variants.len()),
|
||||
};
|
||||
let discriminant = match discriminant_value(&node.inner) {
|
||||
ParsedDiscriminant::Constant(discriminant) => discriminant,
|
||||
ParsedDiscriminant::Successor => match enm.variants.last() {
|
||||
None => Discriminant::zero(),
|
||||
Some(last) => match last.discriminant.checked_succ() {
|
||||
Some(discriminant) => discriminant,
|
||||
None => {
|
||||
let span = &enm.variants_from_header_attr;
|
||||
let msg = format!(
|
||||
"overflow processing discriminant value for variant: {}",
|
||||
decl.name,
|
||||
);
|
||||
return cx.error(span, msg);
|
||||
}
|
||||
},
|
||||
},
|
||||
ParsedDiscriminant::Fail => {
|
||||
let span = &enm.variants_from_header_attr;
|
||||
let msg = format!(
|
||||
"failed to obtain discriminant value for variant: {}",
|
||||
decl.name,
|
||||
);
|
||||
cx.error(span, msg);
|
||||
Discriminant::zero()
|
||||
}
|
||||
};
|
||||
enm.variants.push(Variant {
|
||||
doc: Doc::new(),
|
||||
attrs: OtherAttrs::none(),
|
||||
@ -159,7 +193,7 @@ fn traverse<'a>(
|
||||
cxx: cxx_name,
|
||||
rust: rust_name,
|
||||
},
|
||||
discriminant: unimplemented!(),
|
||||
discriminant,
|
||||
expr: None,
|
||||
});
|
||||
}
|
||||
@ -173,3 +207,33 @@ fn traverse<'a>(
|
||||
let _ = namespace.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
enum ParsedDiscriminant {
|
||||
Constant(Discriminant),
|
||||
Successor,
|
||||
Fail,
|
||||
}
|
||||
|
||||
fn discriminant_value(mut clang: &[Node]) -> ParsedDiscriminant {
|
||||
if clang.is_empty() {
|
||||
// No discriminant expression provided; use successor of previous
|
||||
// descriminant.
|
||||
return ParsedDiscriminant::Successor;
|
||||
}
|
||||
|
||||
loop {
|
||||
if clang.len() != 1 {
|
||||
return ParsedDiscriminant::Fail;
|
||||
}
|
||||
|
||||
let node = &clang[0];
|
||||
match &node.kind {
|
||||
Clang::ImplicitCastExpr => clang = &node.inner,
|
||||
Clang::ConstantExpr(expr) => match Discriminant::from_str(&expr.value) {
|
||||
Ok(discriminant) => return ParsedDiscriminant::Constant(discriminant),
|
||||
Err(_) => return ParsedDiscriminant::Fail,
|
||||
},
|
||||
_ => return ParsedDiscriminant::Fail,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ fn insert(set: &mut DiscriminantSet, discriminant: Discriminant) -> Result<Discr
|
||||
}
|
||||
|
||||
impl Discriminant {
|
||||
const fn zero() -> Self {
|
||||
pub const fn zero() -> Self {
|
||||
Discriminant {
|
||||
sign: Sign::Positive,
|
||||
magnitude: 0,
|
||||
@ -179,6 +179,28 @@ impl Discriminant {
|
||||
magnitude: i.wrapping_abs() as u64,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn checked_succ(self) -> Option<Self> {
|
||||
match self.sign {
|
||||
Sign::Negative => {
|
||||
if self.magnitude == 1 {
|
||||
Some(Discriminant::zero())
|
||||
} else {
|
||||
Some(Discriminant {
|
||||
sign: Sign::Negative,
|
||||
magnitude: self.magnitude - 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
Sign::Positive => match self.magnitude.checked_add(1) {
|
||||
Some(magnitude) => Some(Discriminant {
|
||||
sign: Sign::Positive,
|
||||
magnitude,
|
||||
}),
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Discriminant {
|
||||
|
@ -30,7 +30,6 @@ pub mod types;
|
||||
mod visit;
|
||||
|
||||
use self::attrs::OtherAttrs;
|
||||
use self::discriminant::Discriminant;
|
||||
use self::namespace::Namespace;
|
||||
use self::parse::kw;
|
||||
use self::symbol::Symbol;
|
||||
@ -41,6 +40,7 @@ use syn::{Attribute, Expr, Generics, Lifetime, LitInt, Token, Type as RustType};
|
||||
|
||||
pub use self::atom::Atom;
|
||||
pub use self::derive::{Derive, Trait};
|
||||
pub use self::discriminant::Discriminant;
|
||||
pub use self::doc::Doc;
|
||||
pub use self::names::ForeignName;
|
||||
pub use self::parse::parse_items;
|
||||
|
Loading…
Reference in New Issue
Block a user