Commit d38ffa5f authored by Ryan Hunt's avatar Ryan Hunt
Browse files

Add support for const items

parent 598382f2
const FOO: i32 = 10;
const BAR: &'static libc::c_char = "hello world";
#[repr(C)]
struct Foo {
x: [i32; FOO],
}
#[no_mangle]
extern "C" fn root(x: Foo) { }
......@@ -8,12 +8,13 @@ use std::path;
use std::fs;
use bindgen::config::{Config, Language};
use bindgen::ir::{ItemContainer, Function};
use bindgen::ir::{Constant, ItemContainer, Function};
use bindgen::monomorph::TemplateSpecialization;
use bindgen::writer::{ListType, Source, SourceWriter};
pub struct Bindings {
config: Config,
constants: Vec<Constant>,
items: Vec<ItemContainer>,
functions: Vec<Function>,
template_specializations: Vec<TemplateSpecialization>,
......@@ -21,11 +22,13 @@ pub struct Bindings {
impl Bindings {
pub fn new(config: Config,
constants: Vec<Constant>,
items: Vec<ItemContainer>,
functions: Vec<Function>,
template_specializations: Vec<TemplateSpecialization>) -> Bindings {
Bindings {
config: config,
constants: constants,
items: items,
functions: functions,
template_specializations: template_specializations,
......@@ -89,6 +92,12 @@ impl Bindings {
self.open_namespaces(&mut out);
}
for constant in &self.constants {
out.new_line_if_not_start();
constant.write(&self.config, &mut out);
out.new_line();
}
for item in &self.items {
if item.deref().annotations().bool("no-export").unwrap_or(false) {
continue;
......@@ -96,6 +105,7 @@ impl Bindings {
out.new_line_if_not_start();
match item {
&ItemContainer::Constant(ref x) => x.write(&self.config, &mut out),
&ItemContainer::Enum(ref x) => x.write(&self.config, &mut out),
&ItemContainer::Struct(ref x) => x.write(&self.config, &mut out),
&ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out),
......
......@@ -8,7 +8,7 @@ use syn;
use bindgen::cargo::Cargo;
use bindgen::config::Config;
use bindgen::ir::{AnnotationSet, Cfg, Documentation, Enum, Function};
use bindgen::ir::{AnnotationSet, Cfg, Constant, Documentation, Enum, Function};
use bindgen::ir::{ItemMap, OpaqueItem, Specialization, Struct, Typedef};
use bindgen::library::Library;
use bindgen::rust_lib;
......@@ -80,6 +80,7 @@ impl LibraryBuilder {
result.functions.sort_by(|x, y| x.name.cmp(&y.name));
Ok(Library::new(self.config,
result.constants,
result.enums,
result.structs,
result.opaque_items,
......@@ -91,6 +92,7 @@ impl LibraryBuilder {
#[derive(Debug, Clone)]
struct LibraryParseResult {
constants: ItemMap<Constant>,
enums: ItemMap<Enum>,
structs: ItemMap<Struct>,
opaque_items: ItemMap<OpaqueItem>,
......@@ -103,6 +105,7 @@ impl LibraryParseResult {
fn new() -> LibraryParseResult {
LibraryParseResult {
enums: ItemMap::new(),
constants: ItemMap::new(),
structs: ItemMap::new(),
opaque_items: ItemMap::new(),
typedefs: ItemMap::new(),
......@@ -168,6 +171,14 @@ impl LibraryParseResult {
decl,
abi);
}
syn::ItemKind::Const(ref ty, ref expr) => {
self.load_syn_const(binding_crate_name,
crate_name,
mod_cfg,
item,
ty,
expr);
}
syn::ItemKind::Struct(ref variant, ref generics) => {
self.load_syn_struct(crate_name, mod_cfg, item, variant, generics);
}
......@@ -275,6 +286,42 @@ impl LibraryParseResult {
}
}
/// Loads a `const` declaration
fn load_syn_const(&mut self,
binding_crate_name: &str,
crate_name: &str,
mod_cfg: &Option<Cfg>,
item: &syn::Item,
ty: &syn::Ty,
expr: &syn::Expr) {
if crate_name != binding_crate_name {
info!("Skip {}::{} - (const's outside of the binding crate are not used).",
crate_name,
&item.ident);
return;
}
let const_name = item.ident.to_string();
match Constant::load(const_name.clone(),
ty,
expr,
&item.attrs,
mod_cfg) {
Ok(constant) => {
info!("Take {}::{}.", crate_name, &item.ident);
self.constants.try_insert(constant);
}
Err(msg) => {
warn!("Skip {}::{} - ({})",
crate_name,
&item.ident,
msg);
}
}
}
/// Loads a `struct` declaration
fn load_syn_struct(&mut self,
crate_name: &str,
......
......@@ -13,7 +13,7 @@ use bindgen::writer::SourceWriter;
enum CDeclarator {
Ptr(bool),
Array(u64),
Array(String),
Func(Vec<(Option<String>, CDecl)>, bool),
}
......@@ -92,8 +92,8 @@ impl CDecl {
self.declarators.push(CDeclarator::Ptr(is_const));
self.build_type(t, false);
}
&Type::Array(ref t, sz) => {
self.declarators.push(CDeclarator::Array(sz));
&Type::Array(ref t, ref constant) => {
self.declarators.push(CDeclarator::Array(constant.clone()));
self.build_type(t, false);
}
&Type::FuncPtr(ref ret, ref args) => {
......@@ -164,11 +164,11 @@ impl CDecl {
&CDeclarator::Ptr(..) => {
last_was_pointer = true;
},
&CDeclarator::Array(sz) => {
&CDeclarator::Array(ref constant) => {
if last_was_pointer {
out.write(")");
}
out.write(&format!("[{}]", sz));
out.write(&format!("[{}]", constant));
last_was_pointer = false;
},
......
......@@ -217,7 +217,7 @@ impl StructConfig {
}
/// Settings to apply to generated enums.
#[derive( Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
......@@ -250,6 +250,24 @@ impl EnumConfig {
}
}
/// Settings to apply to generated constants.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct ConstantConfig {
/// Whether a generated constant can be a static const in C++ mode.
pub allow_static_const: bool,
}
impl Default for ConstantConfig {
fn default() -> ConstantConfig {
ConstantConfig {
allow_static_const: true,
}
}
}
/// Settings to apply when parsing.
#[derive( Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
......@@ -323,6 +341,8 @@ pub struct Config {
/// The configuration options for enums
#[serde(rename = "enum")]
pub enumeration: EnumConfig,
#[serde(rename = "const")]
pub constant: ConstantConfig,
// Preprocessor defines to use when generating #ifdef's for #[cfg]
pub defines: HashMap<String, String>,
/// Include doc comments from rust as documentation
......@@ -347,6 +367,7 @@ impl Default for Config {
function: FunctionConfig::default(),
structure: StructConfig::default(),
enumeration: EnumConfig::default(),
constant: ConstantConfig::default(),
defines: HashMap::new(),
documentation: true,
}
......
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::io::Write;
use std::mem;
use syn;
use bindgen::config::{Config, Language};
use bindgen::ir::{AnnotationSet, Cfg, Documentation, Item, ItemContainer, Specialization, Type};
use bindgen::library::Library;
use bindgen::writer::{Source, SourceWriter};
#[derive(Debug, Clone)]
pub struct LiteralExpr(String);
impl LiteralExpr {
pub fn load(expr: &syn::Expr) -> Result<LiteralExpr, String> {
match &expr.node {
&syn::ExprKind::Lit(syn::Lit::Str(ref text, ..)) => {
Ok(LiteralExpr(format!("\"{}\"", text)))
}
&syn::ExprKind::Lit(syn::Lit::Byte(value)) => {
Ok(LiteralExpr(format!("{}", value)))
}
&syn::ExprKind::Lit(syn::Lit::Char(value)) => {
Ok(LiteralExpr(format!("{}", value)))
}
&syn::ExprKind::Lit(syn::Lit::Int(value, ref ty)) => {
match ty {
&syn::IntTy::Usize |
&syn::IntTy::U8 |
&syn::IntTy::U16 |
&syn::IntTy::U32 |
&syn::IntTy::U64 |
&syn::IntTy::Unsuffixed => {
Ok(LiteralExpr(format!("{}", value)))
}
&syn::IntTy::Isize |
&syn::IntTy::I8 |
&syn::IntTy::I16 |
&syn::IntTy::I32 |
&syn::IntTy::I64 => {
unsafe {
Ok(LiteralExpr(format!("{}", mem::transmute::<u64, i64>(value))))
}
}
}
}
&syn::ExprKind::Lit(syn::Lit::Float(ref value, ref _ty)) => {
Ok(LiteralExpr(format!("{}", value)))
}
&syn::ExprKind::Lit(syn::Lit::Bool(value)) => {
Ok(LiteralExpr(format!("{}", value)))
}
_ => Err("Unsupported literal expression.".to_owned())
}
}
}
#[derive(Debug, Clone)]
pub struct Constant {
pub name: String,
pub ty: Type,
pub value: LiteralExpr,
pub cfg: Option<Cfg>,
pub annotations: AnnotationSet,
pub documentation: Documentation,
}
impl Constant {
pub fn load(name: String,
ty: &syn::Ty,
expr: &syn::Expr,
attrs: &Vec<syn::Attribute>,
mod_cfg: &Option<Cfg>) -> Result<Constant, String>
{
let ty = Type::load(ty)?;
if ty.is_none() {
return Err("Cannot have a zero sized const definition.".to_owned());
}
let ty = ty.unwrap();
if !ty.is_primitive_or_ptr_primitive() {
return Err("Cannot have a non primitive const definition.".to_owned());
}
Ok(Constant {
name: name,
ty: ty,
value: LiteralExpr::load(expr)?,
cfg: Cfg::append(mod_cfg, Cfg::load(attrs)),
annotations: AnnotationSet::load(attrs)?,
documentation: Documentation::load(attrs),
})
}
}
impl Item for Constant {
fn name(&self) -> &str {
&self.name
}
fn cfg(&self) -> &Option<Cfg> {
&self.cfg
}
fn annotations(&self) -> &AnnotationSet {
&self.annotations
}
fn annotations_mut(&mut self) -> &mut AnnotationSet {
&mut self.annotations
}
fn container(&self) -> ItemContainer {
ItemContainer::Constant(self.clone())
}
fn specialize(&self, _library: &Library, _aliasee: &Specialization) -> Result<Box<Item>, String> {
unreachable!();
}
}
impl Source for Constant {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
if config.constant.allow_static_const &&
config.language == Language::Cxx
{
if let Type::ConstPtr(..) = self.ty {
out.write("static ");
} else {
out.write("static const ");
}
self.ty.write(config, out);
out.write(&format!(" {} = {};", self.name, self.value.0))
} else {
out.write(&format!("#define {} {}", self.name, self.value.0))
}
}
}
......@@ -7,7 +7,7 @@ use std::mem;
use bindgen::config::Config;
use bindgen::dependencies::Dependencies;
use bindgen::ir::{AnnotationSet, Cfg, Enum, OpaqueItem, Specialization, Struct, Type, Typedef};
use bindgen::ir::{AnnotationSet, Cfg, Constant, Enum, OpaqueItem, Specialization, Struct, Type, Typedef};
use bindgen::library::Library;
use bindgen::monomorph::Monomorphs;
......@@ -29,6 +29,7 @@ pub trait Item {
#[derive(Debug, Clone)]
pub enum ItemContainer {
Constant(Constant),
OpaqueItem(OpaqueItem),
Struct(Struct),
Enum(Enum),
......@@ -39,6 +40,7 @@ pub enum ItemContainer {
impl ItemContainer {
pub fn deref(&self) -> &Item {
match self {
&ItemContainer::Constant(ref x) => x,
&ItemContainer::OpaqueItem(ref x) => x,
&ItemContainer::Struct(ref x) => x,
&ItemContainer::Enum(ref x) => x,
......@@ -59,7 +61,7 @@ pub struct ItemMap<T: Item> {
data: BTreeMap<String, ItemValue<T>>,
}
impl<T: Item> ItemMap<T> {
impl<T: Item + Clone> ItemMap<T> {
pub fn new() -> ItemMap<T> {
ItemMap {
data: BTreeMap::new(),
......@@ -103,6 +105,21 @@ impl<T: Item> ItemMap<T> {
true
}
pub fn to_vec(&self) -> Vec<T> {
let mut result = Vec::with_capacity(self.data.len());
for container in self.data.values() {
match container {
&ItemValue::Cfg(ref items) => {
result.extend_from_slice(items)
}
&ItemValue::Single(ref item) => {
result.push(item.clone());
}
}
}
result
}
pub fn get_items(&self, name: &str) -> Option<Vec<ItemContainer>> {
match self.data.get(name) {
Some(&ItemValue::Cfg(ref items)) => {
......
......@@ -4,6 +4,7 @@
pub mod annotation;
pub mod cfg;
pub mod constant;
pub mod enumeration;
pub mod function;
pub mod item;
......@@ -18,6 +19,7 @@ pub mod documentation;
pub use self::annotation::{AnnotationSet, AnnotationValue};
pub use self::cfg::*;
pub use self::constant::*;
pub use self::enumeration::*;
pub use self::function::*;
pub use self::item::*;
......
......@@ -65,6 +65,9 @@ impl Specialization {
}
match items[0] {
ItemContainer::Constant(ref aliased) => {
aliased.specialize(library, self)
}
ItemContainer::OpaqueItem(ref aliased) => {
aliased.specialize(library, self)
}
......
......@@ -171,7 +171,7 @@ pub enum Type {
Ptr(Box<Type>),
Path(GenericPath),
Primitive(PrimitiveType),
Array(Box<Type>, u64),
Array(Box<Type>, String),
FuncPtr(Box<Type>, Vec<Type>),
}
......@@ -228,7 +228,19 @@ impl Type {
None => return Err("Cannot have an array of zero sized types.".to_owned()),
};
Type::Array(Box::new(converted), size)
Type::Array(Box::new(converted), format!("{}", size))
},
&syn::Ty::Array(ref ty, syn::ConstExpr::Path(ref path)) => {
let converted = Type::load(ty)?;
let converted = match converted {
Some(converted) => converted,
None => return Err("Cannot have an array of zero sized types.".to_owned()),
};
let path = GenericPath::load(path)?;
Type::Array(Box::new(converted), path.name)
},
&syn::Ty::BareFn(ref function) => {
let args = function.inputs.iter()
......@@ -249,6 +261,19 @@ impl Type {
return Ok(Some(converted));
}
pub fn is_primitive_or_ptr_primitive(&self) -> bool {
match self {
&Type::Primitive(..) => true,
&Type::ConstPtr(ref x) => {
match x.as_ref() {
&Type::Primitive(..) => true,
_ => false,
}
},
_ => false,
}
}
pub fn get_root_path(&self) -> Option<Path> {
let mut current = self;
loop {
......@@ -295,8 +320,8 @@ impl Type {
&Type::Primitive(ref primitive) => {
Type::Primitive(primitive.clone())
}
&Type::Array(ref ty, ref size) => {
Type::Array(Box::new(ty.specialize(mappings)), *size)
&Type::Array(ref ty, ref constant) => {
Type::Array(Box::new(ty.specialize(mappings)), constant.clone())
}
&Type::FuncPtr(ref ret, ref args) => {
Type::FuncPtr(Box::new(ret.specialize(mappings)),
......@@ -370,6 +395,9 @@ impl Type {
if let Some(items) = library.get_items(&path.name) {
for item in items {
match item {
ItemContainer::Constant(..) => {
warn!("Cannot instantiate a generic constant.")
},
ItemContainer::OpaqueItem(ref x) => {
x.instantiate_monomorph(&path.generics, out);
},
......
......@@ -8,13 +8,14 @@ use std::mem;
use bindgen::bindings::Bindings;
use bindgen::config::{Config, Language};
use bindgen::dependencies::Dependencies;
use bindgen::ir::{Enum, Function, ItemContainer, ItemMap, Item, OpaqueItem};
use bindgen::ir::{Path, Specialization, Struct, Typedef};
use bindgen::ir::{Constant, Enum, Function, ItemContainer, ItemMap, Item};
use bindgen::ir::{OpaqueItem, Path, Specialization, Struct, Typedef};
use bindgen::monomorph::{Monomorphs, TemplateSpecialization};
#[derive(Debug, Clone)]
pub struct Library {
config: Config,
constants: ItemMap<Constant>,
enums: ItemMap<Enum>,
structs: ItemMap<Struct>,
opaque_items: ItemMap<OpaqueItem>,
......@@ -26,6 +27,7 @@ pub struct Library {
impl Library {
pub fn new(config: Config,
constants: ItemMap<Constant>,
enums: ItemMap<Enum>,
structs: ItemMap<Struct>,
opaque_items: ItemMap<OpaqueItem>,
......@@ -34,6 +36,7 @@ impl Library {
functions: Vec<Function>) -> Library {
Library {
config: config,
constants: constants,
enums: enums,
structs: structs,
opaque_items: opaque_items,
......@@ -66,10 +69,12 @@ impl Library {
dependencies.sort();
let items = dependencies.order;
let constants = self.constants.to_vec();
let functions = mem::replace(&mut self.functions, Vec::new());
let template_specializations = mem::replace(&mut self.template_specializations, Vec::new());
Ok(Bindings::new(self.config.clone(),
constants,
items,
functions,
template_specializations))
......@@ -97,6 +102,9 @@ impl Library {
fn insert_item(&mut self, item: ItemContainer) {
match item {
ItemContainer::Constant(x) => {
self.constants.try_insert(x);
},
ItemContainer::OpaqueItem(x) => {
self.opaque_items.try_insert(x);
},
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment