diff options
Diffstat (limited to 'src/bindgen/library.rs')
-rw-r--r-- | src/bindgen/library.rs | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs new file mode 100644 index 0000000..cb4cfbd --- /dev/null +++ b/src/bindgen/library.rs @@ -0,0 +1,446 @@ +/* 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::collections::HashMap; +use std::path::PathBuf; + +use crate::bindgen::bindings::Bindings; +use crate::bindgen::config::{Config, Language, SortKey}; +use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; +use crate::bindgen::dependencies::Dependencies; +use crate::bindgen::error::Error; +use crate::bindgen::ir::{Constant, Enum, Function, Item, ItemContainer, ItemMap}; +use crate::bindgen::ir::{OpaqueItem, Path, Static, Struct, Typedef, Union}; +use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::ItemType; + +#[derive(Debug, Clone)] +pub struct Library { + config: Config, + constants: ItemMap<Constant>, + globals: ItemMap<Static>, + enums: ItemMap<Enum>, + structs: ItemMap<Struct>, + unions: ItemMap<Union>, + opaque_items: ItemMap<OpaqueItem>, + typedefs: ItemMap<Typedef>, + functions: Vec<Function>, + source_files: Vec<PathBuf>, +} + +impl Library { + #[allow(clippy::too_many_arguments)] + pub fn new( + config: Config, + constants: ItemMap<Constant>, + globals: ItemMap<Static>, + enums: ItemMap<Enum>, + structs: ItemMap<Struct>, + unions: ItemMap<Union>, + opaque_items: ItemMap<OpaqueItem>, + typedefs: ItemMap<Typedef>, + functions: Vec<Function>, + source_files: Vec<PathBuf>, + ) -> Library { + Library { + config, + constants, + globals, + enums, + structs, + unions, + opaque_items, + typedefs, + functions, + source_files, + } + } + + pub fn generate(mut self) -> Result<Bindings, Error> { + self.transfer_annotations(); + self.simplify_standard_types(); + + match self.config.function.sort_by.unwrap_or(self.config.sort_by) { + SortKey::Name => self.functions.sort_by(|x, y| x.path.cmp(&y.path)), + SortKey::None => { /* keep input order */ } + } + + if self.config.language != Language::Cxx { + self.instantiate_monomorphs(); + } + self.remove_excluded(); + if self.config.language == Language::C { + self.resolve_declaration_types(); + } + + self.rename_items(); + + let mut dependencies = Dependencies::new(); + + for function in &self.functions { + function.add_dependencies(&self, &mut dependencies); + } + self.globals.for_all_items(|global| { + global.add_dependencies(&self, &mut dependencies); + }); + self.constants.for_all_items(|constant| { + constant.add_dependencies(&self, &mut dependencies); + }); + for name in &self.config.export.include { + let path = Path::new(name.clone()); + if let Some(items) = self.get_items(&path) { + if dependencies.items.insert(path) { + for item in &items { + item.deref().add_dependencies(&self, &mut dependencies); + } + for item in items { + dependencies.order.push(item); + } + } + } + } + + dependencies.sort(); + + let items = dependencies.order; + let constants = if self.config.export.should_generate(ItemType::Constants) { + let mut constants = self.constants.to_vec(); + match self.config.constant.sort_by.unwrap_or(self.config.sort_by) { + SortKey::Name => constants.sort_by(|x, y| x.path.cmp(&y.path)), + SortKey::None => { /* keep input order */ } + } + constants + } else { + vec![] + }; + + let globals = if self.config.export.should_generate(ItemType::Globals) { + let mut globals = self.globals.to_vec(); + match self.config.constant.sort_by.unwrap_or(self.config.sort_by) { + SortKey::Name => globals.sort_by(|x, y| x.path.cmp(&y.path)), + SortKey::None => { /* keep input order */ } + } + globals + } else { + vec![] + }; + let functions = if self.config.export.should_generate(ItemType::Functions) { + self.functions + } else { + vec![] + }; + + Ok(Bindings::new( + self.config, + self.structs, + self.typedefs, + constants, + globals, + items, + functions, + self.source_files, + false, + )) + } + + pub fn get_items(&self, p: &Path) -> Option<Vec<ItemContainer>> { + macro_rules! find { + ($field:ident, $kind:ident) => { + if self.config.export.should_generate(ItemType::$kind) { + if let Some(x) = self.$field.get_items(p) { + return Some(x); + } + } + }; + } + + find!(enums, Enums); + find!(structs, Structs); + find!(unions, Unions); + find!(opaque_items, OpaqueItems); + find!(typedefs, Typedefs); + + None + } + + pub fn get_config(&self) -> &Config { + &self.config + } + + fn remove_excluded(&mut self) { + let config = &self.config; + // FIXME: interpret `config.export.exclude` as `Path`s. + self.functions + .retain(|x| !config.export.exclude.iter().any(|y| y == x.path().name())); + self.enums + .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name())); + self.structs + .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name())); + self.unions + .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name())); + self.opaque_items + .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name())); + self.typedefs + .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name())); + self.globals + .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name())); + self.constants + .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name())); + } + + fn transfer_annotations(&mut self) { + let mut annotations = HashMap::new(); + + self.typedefs.for_all_items_mut(|x| { + x.transfer_annotations(&mut annotations); + }); + + for (alias_path, annotations) in annotations { + // TODO + let mut transferred = false; + + self.enums.for_items_mut(&alias_path, |x| { + if x.annotations().is_empty() { + *x.annotations_mut() = annotations.clone(); + transferred = true; + } else { + warn!( + "Can't transfer annotations from typedef to alias ({}) \ + that already has annotations.", + alias_path + ); + } + }); + if transferred { + continue; + } + self.structs.for_items_mut(&alias_path, |x| { + if x.annotations().is_empty() { + *x.annotations_mut() = annotations.clone(); + transferred = true; + } else { + warn!( + "Can't transfer annotations from typedef to alias ({}) \ + that already has annotations.", + alias_path + ); + } + }); + if transferred { + continue; + } + self.unions.for_items_mut(&alias_path, |x| { + if x.annotations().is_empty() { + *x.annotations_mut() = annotations.clone(); + transferred = true; + } else { + warn!( + "Can't transfer annotations from typedef to alias ({}) \ + that already has annotations.", + alias_path + ); + } + }); + if transferred { + continue; + } + self.opaque_items.for_items_mut(&alias_path, |x| { + if x.annotations().is_empty() { + *x.annotations_mut() = annotations.clone(); + transferred = true; + } else { + warn!( + "Can't transfer annotations from typedef to alias ({}) \ + that already has annotations.", + alias_path + ); + } + }); + if transferred { + continue; + } + self.typedefs.for_items_mut(&alias_path, |x| { + if x.annotations().is_empty() { + *x.annotations_mut() = annotations.clone(); + transferred = true; + } else { + warn!( + "Can't transfer annotations from typedef to alias ({}) \ + that already has annotations.", + alias_path + ); + } + }); + if transferred { + continue; + } + } + } + + fn rename_items(&mut self) { + let config = &self.config; + + self.globals + .for_all_items_mut(|x| x.rename_for_config(config)); + self.globals.rebuild(); + + self.constants + .for_all_items_mut(|x| x.rename_for_config(config)); + self.constants.rebuild(); + + self.structs + .for_all_items_mut(|x| x.rename_for_config(config)); + self.structs.rebuild(); + + self.unions + .for_all_items_mut(|x| x.rename_for_config(config)); + self.unions.rebuild(); + + self.enums + .for_all_items_mut(|x| x.rename_for_config(config)); + self.enums.rebuild(); + + self.opaque_items + .for_all_items_mut(|x| x.rename_for_config(config)); + self.opaque_items.rebuild(); + + self.typedefs + .for_all_items_mut(|x| x.rename_for_config(config)); + self.typedefs.rebuild(); + + for item in &mut self.functions { + item.rename_for_config(&self.config); + } + } + + fn resolve_declaration_types(&mut self) { + if !self.config.style.generate_tag() { + return; + } + + let mut resolver = DeclarationTypeResolver::default(); + + self.structs.for_all_items(|x| { + x.collect_declaration_types(&mut resolver); + }); + + self.enums.for_all_items(|x| { + x.collect_declaration_types(&mut resolver); + }); + + self.unions.for_all_items(|x| { + x.collect_declaration_types(&mut resolver); + }); + + self.typedefs.for_all_items(|x| { + x.collect_declaration_types(&mut resolver); + }); + + // NOTE: Intentionally last, so that in case there's an opaque type + // which is conflicting with a non-opaque one, the later wins. + self.opaque_items.for_all_items(|x| { + x.collect_declaration_types(&mut resolver); + }); + + self.enums + .for_all_items_mut(|x| x.resolve_declaration_types(&resolver)); + + self.structs + .for_all_items_mut(|x| x.resolve_declaration_types(&resolver)); + + self.unions + .for_all_items_mut(|x| x.resolve_declaration_types(&resolver)); + + self.typedefs + .for_all_items_mut(|x| x.resolve_declaration_types(&resolver)); + + self.globals + .for_all_items_mut(|x| x.resolve_declaration_types(&resolver)); + + for item in &mut self.functions { + item.resolve_declaration_types(&resolver); + } + } + + fn simplify_standard_types(&mut self) { + let config = &self.config; + + self.structs.for_all_items_mut(|x| { + x.simplify_standard_types(config); + }); + self.enums.for_all_items_mut(|x| { + x.simplify_standard_types(config); + }); + self.unions.for_all_items_mut(|x| { + x.simplify_standard_types(config); + }); + self.globals.for_all_items_mut(|x| { + x.simplify_standard_types(config); + }); + self.typedefs.for_all_items_mut(|x| { + x.simplify_standard_types(config); + }); + for x in &mut self.functions { + x.simplify_standard_types(config); + } + } + + fn instantiate_monomorphs(&mut self) { + // Collect a list of monomorphs + let mut monomorphs = Monomorphs::default(); + + self.structs.for_all_items(|x| { + x.add_monomorphs(self, &mut monomorphs); + }); + self.unions.for_all_items(|x| { + x.add_monomorphs(self, &mut monomorphs); + }); + self.enums.for_all_items(|x| { + x.add_monomorphs(self, &mut monomorphs); + }); + self.typedefs.for_all_items(|x| { + x.add_monomorphs(self, &mut monomorphs); + }); + for x in &self.functions { + x.add_monomorphs(self, &mut monomorphs); + } + + // Insert the monomorphs into self + for monomorph in monomorphs.drain_structs() { + self.structs.try_insert(monomorph); + } + for monomorph in monomorphs.drain_unions() { + self.unions.try_insert(monomorph); + } + for monomorph in monomorphs.drain_opaques() { + self.opaque_items.try_insert(monomorph); + } + for monomorph in monomorphs.drain_typedefs() { + self.typedefs.try_insert(monomorph); + } + for monomorph in monomorphs.drain_enums() { + self.enums.try_insert(monomorph); + } + + // Remove structs and opaque items that are generic + self.opaque_items.filter(|x| x.generic_params.len() > 0); + self.structs.filter(|x| x.generic_params.len() > 0); + self.unions.filter(|x| x.generic_params.len() > 0); + self.enums.filter(|x| x.generic_params.len() > 0); + self.typedefs.filter(|x| x.generic_params.len() > 0); + + // Mangle the paths that remain + self.unions + .for_all_items_mut(|x| x.mangle_paths(&monomorphs)); + self.structs + .for_all_items_mut(|x| x.mangle_paths(&monomorphs)); + self.enums + .for_all_items_mut(|x| x.mangle_paths(&monomorphs)); + self.typedefs + .for_all_items_mut(|x| x.mangle_paths(&monomorphs)); + for x in &mut self.functions { + x.mangle_paths(&monomorphs); + } + } +} |