diff options
Diffstat (limited to 'src/parser.rs')
-rw-r--r-- | src/parser.rs | 1516 |
1 files changed, 0 insertions, 1516 deletions
diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index 0e531420..00000000 --- a/src/parser.rs +++ /dev/null @@ -1,1516 +0,0 @@ -#![allow(non_upper_case_globals)] - -use std::collections::{HashMap, HashSet}; -use hacks::refcell::RefCell; -use std::rc::Rc; -use std::path::Path; -use std::cmp; - -use syntax::abi; - -use types as il; -use types::*; -use clang as cx; -use clang::{ast_dump, Comment, Cursor, Diagnostic, TranslationUnit, type_to_str, kind_to_str}; -use clangll::*; - -use super::Logger; - -#[derive(Clone)] -pub struct ClangParserOptions { - pub builtin_names: HashSet<String>, - pub builtins: bool, - pub match_pat: Vec<String>, - pub emit_ast: bool, - pub fail_on_unknown_type: bool, - pub ignore_functions: bool, - pub ignore_methods: bool, - pub enable_cxx_namespaces: bool, - pub class_constants: bool, - pub namespaced_constants: bool, - pub override_enum_ty: Option<il::IKind>, - pub clang_args: Vec<String>, - pub opaque_types: Vec<String>, - pub blacklist_type: Vec<String>, - pub msvc_mangling: bool, -} - -struct ClangParserCtx<'a> { - options: ClangParserOptions, - name: HashMap<Cursor, Global>, - builtin_defs: Vec<Cursor>, - module_map: ModuleMap, - current_module_id: ModuleId, - /// This member is used to track down if we're in a namespace if the - /// enable_cxx_namespaces option is disabled. - namespace_depth: usize, - current_translation_unit: TranslationUnit, - logger: &'a (Logger+'a), - err_count: i32, - anonymous_modules_found: usize, -} - -impl<'a> ClangParserCtx<'a> { - fn module(&self, id: &ModuleId) -> &Module { - self.module_map.get(id).expect("Module not found!") - } - - fn current_module(&self) -> &Module { - self.module(&self.current_module_id) - } - - fn in_root_namespace(&self) -> bool { - self.namespace_depth == 0 - } - - fn current_module_mut(&mut self) -> &mut Module { - self.module_map.get_mut(&self.current_module_id).expect("Module not found!") - } -} - -fn cursor_link_name(_: &mut ClangParserCtx, cursor: &Cursor) -> String { - // Try to undo backend linkage munging (prepended _, generally) - let mut mangling = cursor.mangling(); - if cfg!(target_os = "macos") { - mangling.remove(0); - } - mangling -} - -fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool { - let (file, _, _, _) = cursor.location().location(); - - let name = match file.name() { - None => return ctx.options.builtins, - Some(name) => name, - }; - - if ctx.options.match_pat.is_empty() { - return true; - } - - let name = name.replace("\\", "/"); - ctx.options.match_pat.iter().any(|pat| name.contains(pat)) -} - -fn conv_template_type_parameter(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Type { - assert_eq!(cursor.kind(), CXCursor_TemplateTypeParameter); - let ty = conv_ty(ctx, &cursor.cur_type(), cursor); - let layout = Layout::new(ty.size(), ty.align()); - TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout)))) -} - -fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { - let cursor = cursor.canonical(); - let override_enum_ty = ctx.options.override_enum_ty; - let new_decl = !ctx.name.contains_key(&cursor); - - let decl = if new_decl { - let spelling = cursor.spelling(); - let comment = cursor.raw_comment(); - let (file, _, _, _) = cursor.location().location(); - let ty = cursor.cur_type(); - let layout = Layout::from_ty(&ty); - let filename = match Path::new(&file.name().unwrap_or("".to_owned())).file_name() { - Some(name) => name.to_string_lossy().replace(".", "_"), - _ => "".to_string() - }; - let glob_decl = match cursor.kind() { - CXCursor_UnionDecl | - CXCursor_ClassTemplate | - CXCursor_ClassDecl | - CXCursor_StructDecl => { - let anno = Annotations::new(&cursor); - - let kind = match cursor.kind() { - CXCursor_UnionDecl => CompKind::Union, - CXCursor_ClassTemplate => { - match cursor.template_kind() { - CXCursor_UnionDecl => CompKind::Union, - _ => CompKind::Struct, - } - } - _ => CompKind::Struct, - }; - - let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling); - let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling); - - let mut has_non_type_template_params = false; - let args = match ty.num_template_args() { - // In forward declarations, etc, they are in the ast... sigh - -1 => { - let mut args = vec![]; - cursor.visit(|c, _| { - if c.kind() == CXCursor_TemplateTypeParameter { - args.push(conv_template_type_parameter(ctx, c)); - } - CXChildVisit_Continue - }); - args - } - len => { - let mut list = Vec::with_capacity(len as usize); - for i in 0..len { - let arg_type = ty.template_arg_type(i); - if arg_type.kind() != CXType_Invalid { - list.push(conv_ty(ctx, &arg_type, &cursor)); - } else { - has_non_type_template_params = true; - ctx.logger.warn("warning: Template parameter is not a type"); - } - } - list - } - }; - - let mut ci = CompInfo::new(spelling, ctx.current_module_id, - filename, comment, kind, vec![], - layout, anno); - ci.parser_cursor = Some(cursor); - - // If it's an instantiation of another template, - // find the canonical declaration to find the module - // it belongs to and if it's opaque. - let parent = cursor.specialized(); - if let Some(parent) = ctx.name.get(&parent) { - ci.ref_template = Some(parent.clone().to_type()) - } - - ci.opaque = opaque; - ci.hide = hide; - ci.args = args; - ci.has_non_type_template_params = has_non_type_template_params; - - let ci = Rc::new(RefCell::new(ci)); - GCompDecl(ci) - } - CXCursor_EnumDecl => { - let kind = match override_enum_ty { - Some(t) => t, - None => match cursor.enum_type().kind() { - CXType_SChar | CXType_Char_S => ISChar, - CXType_UChar | CXType_Char_U => IUChar, - CXType_UShort => IUShort, - CXType_UInt => IUInt, - CXType_ULong => IULong, - CXType_ULongLong => IULongLong, - CXType_Short => IShort, - CXType_Int => IInt, - CXType_Long => ILong, - CXType_LongLong => ILongLong, - _ => IInt, - } - }; - - let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, ctx.current_module_id, filename, kind, vec!(), layout))); - GEnumDecl(ei) - } - CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => { - let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling); - let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling); - let mut ti = TypeInfo::new(spelling, ctx.current_module_id, TVoid, layout); - ti.opaque = opaque; - ti.hide = hide; - - let ti = Rc::new(RefCell::new(ti)); - GType(ti) - } - CXCursor_VarDecl => { - let mangled = cursor_link_name(ctx, &cursor); - let is_const = ty.is_const(); - let ty = conv_ty_resolving_typedefs(ctx, &ty, &cursor, true); - let mut vi = VarInfo::new(spelling, mangled, comment, ty); - vi.is_const = is_const; - cursor.visit(|c, _: &Cursor| { - vi.val = visit_literal(c, &ctx.current_translation_unit); - CXChildVisit_Continue - }); - GVar(Rc::new(RefCell::new(vi))) - } - CXCursor_MacroDefinition => { - let vi = Rc::new(RefCell::new(VarInfo::new(spelling, String::new(), comment, TVoid))); - GVar(vi) - } - CXCursor_FunctionDecl => { - let mangled = cursor_link_name(ctx, &cursor); - let vi = Rc::new(RefCell::new(VarInfo::new(spelling, mangled, comment, TVoid))); - GFunc(vi) - } - _ => GOther, - }; - - ctx.name.insert(cursor, glob_decl.clone()); - glob_decl - } else { - ctx.name.get(&cursor).unwrap().clone() - }; - - if new_decl && ctx.options.builtin_names.contains(&cursor.spelling()) { - ctx.builtin_defs.push(cursor); - } - - decl -} - -fn opaque_decl(ctx: &mut ClangParserCtx, decl: &Cursor) { - let spelling = decl.spelling(); - let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling); - - if hide { - return; - } - - let name = decl_name(ctx, decl); - ctx.current_module_mut().globals.push(name); -} - -fn fwd_decl<F: FnOnce(&mut ClangParserCtx)->()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) { - let def = cursor.definition(); - if cursor == &def { - f(ctx); - } else if def.kind() == CXCursor_NoDeclFound || - def.kind() == CXCursor_InvalidFile { - opaque_decl(ctx, cursor); - } -} - -fn get_abi(cc: Enum_CXCallingConv) -> abi::Abi { - match cc { - CXCallingConv_Default => abi::Abi::C, - CXCallingConv_C => abi::Abi::C, - CXCallingConv_X86StdCall => abi::Abi::Stdcall, - CXCallingConv_X86FastCall => abi::Abi::Fastcall, - CXCallingConv_AAPCS => abi::Abi::Aapcs, - CXCallingConv_X86_64Win64 => abi::Abi::Win64, - other => panic!("unsupported calling convention: {}", other), - } -} - -fn conv_ptr_ty_resolving_typedefs(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor, - is_ref: bool, - layout: Layout, - resolve_typedefs: bool) -> il::Type { - let is_const = ty.is_const(); - match ty.kind() { - CXType_Void => { - return TPtr(Box::new(TVoid), is_const, is_ref, layout) - } - CXType_Unexposed | - CXType_FunctionProto | - CXType_FunctionNoProto => { - let ret_ty = ty.ret_type(); - return if ret_ty.kind() != CXType_Invalid { - TFuncPtr(mk_fn_sig(ctx, ty, cursor)) - } else if cursor.kind() == CXCursor_VarDecl { - let can_ty = ty.canonical_type(); - conv_ty_resolving_typedefs(ctx, &can_ty, cursor, resolve_typedefs) - } else { - TPtr(Box::new(conv_decl_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs)), ty.is_const(), is_ref, layout) - }; - } - CXType_Typedef => { - let decl = ty.declaration(); - let def_ty = decl.typedef_type(); - if def_ty.kind() == CXType_FunctionProto || - def_ty.kind() == CXType_FunctionNoProto { - return TPtr(Box::new(conv_ptr_ty_resolving_typedefs(ctx, &def_ty, cursor, is_ref, layout, resolve_typedefs)), is_const, is_ref, layout); - } else { - return TPtr(Box::new(conv_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs)), is_const, is_ref, layout); - } - } - _ => return TPtr(Box::new(conv_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs)), is_const, is_ref, layout), - } -} - -fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::FuncSig { - mk_fn_sig_resolving_typedefs(ctx, ty, cursor, &[]) -} - -fn mk_fn_sig_resolving_typedefs(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor, - typedefs: &[String]) -> il::FuncSig { - let args_lst: Vec<(String, il::Type)> = match cursor.kind() { - CXCursor_FunctionDecl | CXCursor_CXXMethod => { - // For CXCursor_FunctionDecl, cursor.args() is the reliable way to - // get parameter names and types. - cursor.args().iter().map(|arg| { - let arg_name = arg.spelling(); - let arg_ty = arg.cur_type(); - let is_class_typedef = arg_ty.sanitized_spelling_in(typedefs); - (arg_name, conv_ty_resolving_typedefs(ctx, &arg_ty, arg, is_class_typedef)) - }).collect() - } - _ => { - // For non-CXCursor_FunctionDecl, visiting the cursor's children is - // the only reliable way to get parameter names. - let mut args_lst = vec!(); - cursor.visit(|c: &Cursor, _: &Cursor| { - if c.kind() == CXCursor_ParmDecl { - let is_class_typedef = c.cur_type().sanitized_spelling_in(typedefs); - args_lst.push((c.spelling(), conv_ty_resolving_typedefs(ctx, &c.cur_type(), c, is_class_typedef))); - } - CXChildVisit_Continue - }); - args_lst - } - }; - - let ret_ty = Box::new(conv_ty(ctx, &ty.ret_type(), cursor)); - let abi = get_abi(ty.call_conv()); - - // Function is presumed unsafe if it takes a pointer argument. - let is_unsafe = args_lst.iter().any(|arg| match arg.1 { - TPtr(..) => true, - _ => false - }); - - il::FuncSig { - ret_ty: ret_ty, - args: args_lst, - is_variadic: ty.is_variadic(), - is_safe: !is_unsafe, - abi: abi, - } -} - -fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor, - resolve_typedefs: bool) -> il::Type { - let ty_decl = ty.declaration(); - // println!("conv_ty_decl: `{}`, ty kind {}: {}, decl `{}` kind {}: {}", cursor.spelling(), ty.kind(), type_to_str(ty.kind()), ty_decl.spelling(), ty_decl.kind(), kind_to_str(ty_decl.kind())); - return match ty_decl.kind() { - CXCursor_StructDecl | - CXCursor_UnionDecl | - CXCursor_ClassTemplate | - CXCursor_ClassDecl => { - let decl = decl_name(ctx, &ty_decl); - // NB: This will only return a number greater than 0 if this is a **full** class - // template specialization. - // - // If the cursor kind is CXCursor_ClassTemplate, this will still return -1 - // and we'll have to keep traversing the cursor. - let args = match ty.num_template_args() { - -1 => vec![], - len => { - let mut list = Vec::with_capacity(len as usize); - for i in 0..len { - let arg_type = ty.template_arg_type(i); - if arg_type.kind() != CXType_Invalid { - list.push(conv_ty(ctx, &arg_type, &cursor)); - } else { - ctx.logger.warn("warning: Template parameter is not a type"); - } - } - list - } - }; - - let ci = decl.compinfo(); - // NB: Args might be filled from decl_name, - // it's important not to override - // - // We might incur in double borrows here. If that's the case, we're - // already scanning the compinfo, and we'd get the args from the - // ast. - use hacks::refcell::BorrowState; - if !args.is_empty() && ci.borrow_state() == BorrowState::Unused { - ci.borrow_mut().args = args; - - // XXX: This is a super-dumb way to get the spesialisation, - // but it seems to be the only one that'd work here... - cursor.visit(|c, _: &Cursor| { - if c.kind() == CXCursor_TemplateRef { - let decl = decl_name(ctx, &c.referenced()); - ci.borrow_mut().ref_template = Some(decl.to_type()); - } - CXChildVisit_Continue - }); - } - - TComp(ci) - } - CXCursor_EnumDecl => { - let decl = decl_name(ctx, &ty_decl); - let ei = decl.enuminfo(); - TEnum(ei) - } - CXCursor_TypeAliasDecl | - CXCursor_TypedefDecl => { - if resolve_typedefs { - return conv_ty_resolving_typedefs(ctx, &ty_decl.typedef_type(), &ty_decl.typedef_type().declaration(), resolve_typedefs); - } - - let decl = decl_name(ctx, &ty_decl); - let ti = decl.typeinfo(); - TNamed(ti) - } - CXCursor_NoDeclFound => { - let canonical = ty.canonical_type(); - let kind = canonical.kind(); - if kind != CXType_Invalid && kind != CXType_Unexposed { - conv_ty_resolving_typedefs(ctx, &canonical, &ty_decl, resolve_typedefs) - } else { - let layout = Layout::from_ty(ty); - TNamed(Rc::new(RefCell::new(TypeInfo::new(ty.spelling().replace("const ", ""), ctx.current_module_id, TVoid, layout)))) - } - } - _ => { - let fail = ctx.options.fail_on_unknown_type; - log_err_warn(ctx, - &format!("unsupported decl `{}` ({})", - kind_to_str(ty_decl.kind()), ty_decl.location() - ), - fail - ); - TVoid - } - }; -} - -fn conv_ty(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor) -> il::Type { - conv_ty_resolving_typedefs(ctx, ty, cursor, false) -} - -fn conv_ty_resolving_typedefs(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor, - resolve_typedefs: bool) -> il::Type { - let layout = Layout::from_ty(&ty); - // println!("conv_ty: `{}` layout: {:?}, kind {}: {}", cursor.spelling(), layout, ty.kind(), type_to_str(ty.kind())); - - match ty.kind() { - CXType_Void => TVoid, - CXType_Invalid => { - log_err_warn(ctx, - &format!("invalid type `{}` ({})", - cursor.spelling(), cursor.location() - ), - false - ); - TVoid - } - CXType_Bool => TInt(IBool, layout), - CXType_SChar | - CXType_Char_S => TInt(ISChar, layout), - CXType_UChar | - CXType_Char_U => TInt(IUChar, layout), - CXType_WChar => TInt(IShort, layout), - CXType_Char16 | - CXType_UShort => TInt(IUShort, layout), - CXType_UInt => TInt(IUInt, layout), - CXType_ULong => TInt(IULong, layout), - CXType_ULongLong => TInt(IULongLong, layout), - CXType_Short => TInt(IShort, layout), - CXType_Int => TInt(IInt, layout), - CXType_Long => TInt(ILong, layout), - CXType_LongLong => TInt(ILongLong, layout), - CXType_Float => TFloat(FFloat, layout), - CXType_Double => TFloat(FDouble, layout), - CXType_LongDouble => TFloat(FDouble, layout), - CXType_Pointer => conv_ptr_ty_resolving_typedefs(ctx, &ty.pointee_type(), cursor, false, layout, resolve_typedefs), - CXType_LValueReference => conv_ptr_ty_resolving_typedefs(ctx, &ty.pointee_type(), cursor, true, layout, resolve_typedefs), - // XXX DependentSizedArray is wrong - CXType_VariableArray | - CXType_DependentSizedArray | - CXType_IncompleteArray => { - conv_ptr_ty_resolving_typedefs(ctx, &ty.elem_type(), cursor, false, layout, resolve_typedefs) - } - CXType_FunctionProto => TFuncProto(mk_fn_sig(ctx, ty, cursor)), - CXType_Record | - CXType_Typedef | - CXType_Unexposed | - CXType_Enum => conv_decl_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs), - CXType_ConstantArray => TArray(Box::new(conv_ty_resolving_typedefs(ctx, &ty.elem_type(), cursor, resolve_typedefs)), ty.array_size(), layout), - #[cfg(not(feature="llvm_stable"))] - CXType_Elaborated => conv_ty_resolving_typedefs(ctx, &ty.named(), cursor, resolve_typedefs), - _ => { - let fail = ctx.options.fail_on_unknown_type; - log_err_warn(ctx, - &format!("unsupported type `{}` ({})", - type_to_str(ty.kind()), cursor.location() - ), - fail - ); - TVoid - }, - } -} - -fn opaque_ty(ctx: &mut ClangParserCtx, ty: &cx::Type) { - if ty.kind() == CXType_Record || ty.kind() == CXType_Enum { - let decl = ty.declaration(); - let def = decl.definition(); - if def.kind() == CXCursor_NoDeclFound || - def.kind() == CXCursor_InvalidFile { - opaque_decl(ctx, &decl); - } - } -} - -#[derive(Copy, PartialEq, Clone, Debug)] -pub enum Accessor { - None, - Regular, - Unsafe, - Immutable, -} - -#[derive(Clone, PartialEq, Debug)] -pub struct Annotations { - opaque: bool, - hide: bool, - use_as: Option<String>, - /// Disable deriving copy/clone on this struct. - no_copy: bool, - // In the None case we fall back to the value specified - // in the enclosing decl - private: Option<bool>, - accessor: Option<Accessor>, -} - -fn parse_accessor(s: &str) -> Accessor { - match s { - "false" => Accessor::None, - "unsafe" => Accessor::Unsafe, - "immutable" => Accessor::Immutable, - _ => Accessor::Regular, - } -} - -impl Annotations { - fn new(cursor: &Cursor) -> Annotations { - let mut anno = Annotations { - opaque: false, - hide: false, - use_as: None, - no_copy: false, - private: None, - accessor: None - }; - - anno.parse(&cursor.comment()); - anno - } - - fn parse(&mut self, comment: &Comment) { - if comment.kind() == CXComment_HTMLStartTag && - comment.get_tag_name() == "div" && - comment.get_num_tag_attrs() > 1 && - comment.get_tag_attr_name(0) == "rustbindgen" { - for i in 0..comment.get_num_tag_attrs() { - let name = comment.get_tag_attr_name(i); - match name.as_str() { - "opaque" => self.opaque = true, - "hide" => self.hide = true, - "replaces" => self.use_as = Some(comment.get_tag_attr_value(i)), - "nocopy" => self.no_copy = true, - "private" => self.private = Some(comment.get_tag_attr_value(i) != "false"), - "accessor" => { - self.accessor = Some(parse_accessor(&comment.get_tag_attr_value(i))) - }, - _ => (), - } - } - } - - for i in 0..comment.num_children() { - self.parse(&comment.get_child(i)); - } - } -} - -/// Recursively visits a cursor that represents a composite (struct or union) -/// type and fills members with CompMember instances representing the fields and -/// nested composites that make up the visited composite. -fn visit_composite(cursor: &Cursor, parent: &Cursor, - ctx: &mut ClangParserCtx, - ci: &mut CompInfo) -> Enum_CXVisitorResult { - assert!(ci.parser_cursor.is_some()); - fn is_bitfield_continuation(field: &il::FieldInfo, _ty: &il::Type, width: u32) -> bool { - match (&field.bitfields, field.ty.layout()) { - (&Some(ref bitfields), Some(layout)) => { - let actual_width = bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w); - actual_width + width <= (layout.size * 8) as u32 - }, - _ => false - } - } - - match cursor.kind() { - CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => { - ci.typedefs.push(cursor.spelling().to_owned()); - } - CXCursor_FieldDecl => { - let anno = Annotations::new(cursor); - if anno.hide { - return CXChildVisit_Continue; - } - - let is_class_typedef = cursor.cur_type().sanitized_spelling_in(&ci.typedefs); - let mutable = cursor.is_mutable_field(); - - let cursor_ty = cursor.cur_type(); - - // NB: Overwritten in the case of non-integer bitfield - let mut ty = conv_ty_resolving_typedefs(ctx, - &cursor_ty, - cursor, - is_class_typedef); - - - use hacks::refcell::BorrowState; - if let Some(child_ci) = ty.get_outermost_composite() { - if let BorrowState::Unused = child_ci.borrow_state() { - let mut child_ci = child_ci.borrow_mut(); - let child_cursor = child_ci.parser_cursor.unwrap(); - - // TODO: This is lame, ideally we should use cursors. - // The problem this loop is trying to solve is - // tests/headers/inner_template_self.hpp, and templates with - // incomplete types. - // - // The problem with this is that, in the first case (see the - // CXCursor_ClassDecl branch below) clang treats the *prev* - // field as a Class Declaration instead of a Class Template, - // so we have to check now for the name and the module id. - // - // Ideally, some method like `semantic_parent` or - // `lexical_parent` should return the reference to the - // class, but I've tried everything I could think about and - // failed miserably. - // - // Also, there could be more complex cases, like a templated - // type in an inner type declaration, that this is - // completely unable to catch. - // - // In the second case (the CXCursor_ClassTemplate branch), - // we're not able to retrieve the template parameters of an - // incomplete type via the declaration or anything like - // that. We can inspect the AST and deduct them though, - // since there's a leading CXCursor_TemplateRef. - if child_ci.args.is_empty() && child_cursor.kind() == CXCursor_ClassDecl { - // println!("child: {:?} {:?}, {:?}, {:?}", cursor.spelling(), - // type_to_str(cursor_ty.kind()), - // type_to_str(child_cursor.cur_type().kind()), - // kind_to_str(child_cursor.kind())); - if child_ci.name == ci.name && - child_ci.module_id == ci.module_id { - child_ci.args = ci.args.clone(); - } - } - - if child_cursor.kind() == CXCursor_ClassTemplate { - // We need to take into account the possibly different - // type template names, so we need to clear them and - // re-scan. - child_ci.args.clear(); - let mut found_invalid_template_ref = false; - cursor.visit(|c, _| { - // println!("ichild: {:?} {:?}, {:?}", c.spelling(), - // kind_to_str(c.kind()), - // type_to_str(c.cur_type().kind())); - if c.kind() == CXCursor_TemplateRef && - c.cur_type().kind() == CXType_Invalid { - found_invalid_template_ref = true; - } - if found_invalid_template_ref && - c.kind() == CXCursor_TypeRef { - child_ci.args.push(TNamed(Rc::new(RefCell::new( - TypeInfo::new(c.spelling(), - ctx.current_module_id, - TVoid, - Layout::zero()))))); - } - CXChildVisit_Continue - }) - } - } - } - - let comment = cursor.raw_comment(); - - let (name, bitfields) = match (cursor.bit_width(), ci.members.last_mut()) { - // The field is a continuation of an exising bitfield - (Some(width), Some(&mut il::CompMember::Field(ref mut field))) - if is_bitfield_continuation(field, &ty, width) => { - - // println!("found bitfield continuation {} (width: {})", cursor.spelling(), width); - - field.bitfields.as_mut().unwrap().push((cursor.spelling(), width)); - return CXChildVisit_Continue; - }, - // The field is the start of a new bitfield - (Some(width), _) => { - // Bitfields containing enums are not supported by the c standard - // https://stackoverflow.com/questions/11983231/is-it-safe-to-use-an-enum-in-a-bit-field - - match ty { - il::TInt(..) => {}, - _ => { - // NOTE: We rely on the name of the type converted - // to rust types, and on the alignment. - let bits = cmp::max(width, ty.size() as u32 * 8); - let layout_size = cmp::max(1, bits.next_power_of_two() / 8) as usize; - - let msg = format!("Enums in bitfields are not supported ({}::{}). Trying to recover with width: {}", - parent.spelling(), cursor.spelling(), layout_size * 8); - ctx.logger.warn(&msg); - - let name = match layout_size { - 1 => "uint8_t", - 2 => "uint16_t", - 4 => "uint32_t", - 8 => "uint64_t", - _ => panic!("bitfield width not supported: {}", layout_size), - }; - - // NB: We rely on the ULongLong not being translated - // (using the common uintxx_t name) - let ti = TypeInfo::new(name.into(), - ctx.current_module_id, - TInt(IKind::IULongLong, Layout::new(layout_size, layout_size)), - Layout::new(layout_size, layout_size)); - ty = TNamed(Rc::new(RefCell::new(ti))) - } - } - ("".to_owned(), Some(vec![(cursor.spelling(), width)])) - }, - // The field is not a bitfield - (None, _) => (cursor.spelling(), None) - }; - - // The Clang C api does not fully expose composite fields, but it - // does expose them in a way that can be detected. When the current - // field kind is TComp, TPtr or TArray and the previous member is a - // composite type - the same type as this field - then this is a - // composite field. e.g.: - // - // struct foo { - // union { - // int a; - // char b; - // } bar; - // }; - // - // struct foo { - // union { - // int a; - // char b; - // } **bar; - // }; - // - // struct foo { - // union { - // int a; - // char b; - // } bar[3][2]; - // }; - // - - //let is_composite = match (inner_composite(&ty), ci.members.last()) { - // (Some(ty_compinfo), Some(&CompMember::Comp(ref c))) => { - // c.borrow().deref() as *const _ == ty_compinfo.borrow().deref() as *const _ - // }, - // _ => false - //}; - - if let Some(&mut CompMember::Field(ref mut info)) = ci.members.last_mut() { - if bitfields.is_none() && info.bitfields.is_none() { - let should_replace = if let TComp(ref ci) = info.ty { - if ci.borrow().was_unnamed && ty.was_unnamed() && - Some(&ci.borrow().name) == ty.name().as_ref() { - true - } else { - false - } - } else { - false - }; - - if should_replace { - *info = FieldInfo::new(name, ty, comment, bitfields, mutable); - info.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false)); - info.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None)); - return CXChildVisit_Continue; - } - } - } - - let mut field = FieldInfo::new(name, ty, comment, bitfields, mutable); - field.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false)); - field.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None)); - ci.members.push(CompMember::Field(field)); - } - CXCursor_StructDecl | - CXCursor_UnionDecl | - CXCursor_ClassTemplate | - CXCursor_ClassDecl => { - fwd_decl(ctx, cursor, |ctx_| { - // If the struct is anonymous (i.e. declared here) then it - // cannot be used elsewhere and so does not need to be added - // to globals otherwise it will be declared later and a global. - let decl = decl_name(ctx_, cursor); - let ci2 = decl.compinfo(); - - // Mangle the name to prevent multiple definitions - // of the same inner type to cause conflicts - let new_name = [&*ci.name, &*ci2.borrow().name].join("_").to_owned(); - ci2.borrow_mut().name = new_name; - - // This clear() is needed because of the speculation we do on - // incomplete types inside visit_composite() members. - // - // If this type ends up being complete, we're going to really - // parse them now, so we should reset them. - ci2.borrow_mut().args.clear(); - - // Propagate template arguments and typedefs to inner structs - ci2.borrow_mut().args.extend(ci.args.clone().into_iter()); - ci2.borrow_mut().typedefs.extend(ci.typedefs.clone().into_iter()); - - cursor.visit(|c, p| { - let mut ci_ = ci2.borrow_mut(); - visit_composite(c, p, ctx_, &mut ci_) - }); - - ci.members.push(CompMember::Comp(decl.compinfo())); - - // Anonymous structs are legal in both C++ and C11 - if ci2.borrow().was_unnamed { - let ci2b = ci2.borrow(); - let field = FieldInfo::new(ci2b.name.clone(), TComp(ci2.clone()), ci2b.comment.clone(), None, false); - ci.members.push(CompMember::Field(field)); - } - }); - } - CXCursor_PackedAttr => { - ci.set_packed(true); - } - CXCursor_TemplateTypeParameter => { - ci.args.push(conv_template_type_parameter(ctx, cursor)); - } - CXCursor_EnumDecl => { - let anno = Annotations::new(cursor); - - fwd_decl(ctx, cursor, |ctx_| { - let decl = decl_name(ctx_, cursor); - let ei = decl.enuminfo(); - // Mangle the name to avoid name conflicts with inner types - let new_name = [&*ci.name, &*ei.borrow().name].join("_").to_owned(); - ei.borrow_mut().name = new_name; - ei.borrow_mut().comment = cursor.raw_comment(); - cursor.visit(|c, _: &Cursor| { - let mut ei_ = ei.borrow_mut(); - visit_enum(c, &mut ei_.items) - }); - if anno.opaque { - ei.borrow_mut().items = vec!(); - } - ci.members.push(CompMember::Enum(ei)); - }); - } - CXCursor_CXXBaseSpecifier => { - let ty = conv_ty(ctx, &cursor.cur_type(), cursor); - let fieldname = if ci.members.is_empty() { - "_base".to_string() - } else { - format!("_base{}", ci.members.len()) - }; - let found_virtual_base = if ci.members.is_empty() { - false - } else if let CompMember::Field(ref fi) = ci.members[0] { - if let TComp(ref ci2) = fi.ty { - ci2.borrow().has_vtable - } else { - false - } - } else { - false - }; - - if let TComp(ref info) = ty { - ci.has_nonempty_base |= !info.borrow().members.is_empty(); - ci.has_destructor |= info.borrow().has_destructor; - ci.typedefs.extend(info.borrow().typedefs.clone().into_iter()); - } - - let field = FieldInfo::new(fieldname, ty, "".to_owned(), None, false); - if !found_virtual_base && cursor.is_virtual_base() { - ci.members.insert(0, CompMember::Field(field)); - ci.has_vtable = true; - } else { - ci.members.push(CompMember::Field(field)); - } - ci.base_members += 1; - } - CXCursor_CXXMethod => { - // Make sure to mark has_vtable properly, even if we - // would otherwise skip this method due to linkage/visibility. - if cursor.method_is_virtual() { - ci.has_vtable = true; - } - - let linkage = cursor.linkage(); - if linkage != CXLinkage_External { - return CXChildVisit_Continue; - } - - let visibility = cursor.visibility(); - if visibility != CXVisibility_Default { - return CXChildVisit_Continue; - } - - if cursor.is_inlined_function() { - return CXChildVisit_Continue; - } - - // XXX no methods yet for templates - if !ci.args.is_empty() { - return CXChildVisit_Continue; - } - - if cursor.access_specifier() == CX_CXXPrivate { - return CXChildVisit_Continue; - } - - let spelling = cursor.spelling(); - if spelling.len() > 8 && - &(spelling)[..8] == "operator" { - return CXChildVisit_Continue; - } - - fn is_override(ci: &CompInfo, sig: &Type, name: &str) -> bool { - for vm in ci.vmethods.iter() { - if vm.name == name && &vm.ty == sig { - return true; - } - } - for base in ci.members[..ci.base_members].iter() { - let base = match *base { - CompMember::Field(ref fi) => { - match fi.ty { - TComp(ref ci) => ci.clone(), - _ => continue, - } - }, - _ => unreachable!() - }; - if is_override(&*base.borrow(), sig, name) { - return true; - } - } - return false; - } - - let mut sig = mk_fn_sig_resolving_typedefs(ctx, &cursor.cur_type(), cursor, &ci.typedefs); - if !cursor.method_is_static() { - // XXX what have i done - if cursor.method_is_virtual() { - sig.args.insert(0, ("this".to_string(),TPtr(Box::new(TVoid), cursor.cur_type().is_const(), false, Layout::zero()))); - } else { - // XXX This is weak and doesn't work if names are mangled further, but... - // We can't have access to the current Rc from here, so we can't pass the type - // here. - // - // Also, it would form an rc cycle. - // - // Possibly marking the "this" attribute with TOther or a similar marked value - // would be a better choice. - sig.args.insert(0, ("this".to_string(), - TPtr(Box::new(TNamed(Rc::new(RefCell::new(TypeInfo::new(ci.name.clone(), ctx.current_module_id, TVoid, Layout::zero()))))), cursor.cur_type().is_const(), false, Layout::zero()))); - } - } - - // XXX with final classes we can optimize a bit - let sig = TFuncPtr(sig); - if is_override(ci, &sig, &spelling) { - return CXChildVisit_Continue; - } - - let mut vi = VarInfo::new(spelling, cursor_link_name(ctx, &cursor), cursor.raw_comment(), sig); - vi.is_static = cursor.method_is_static(); - vi.is_const = cursor.cur_type().is_const(); - - if ctx.options.ignore_methods { - return CXChildVisit_Continue; - } - - if cursor.method_is_virtual() { - ci.vmethods.push(vi); - } else { - ci.methods.push(vi); - } - } - CXCursor_Destructor => { - ci.has_destructor = true; - // Propagate the change to the parent - if let Some(ref t) = ci.ref_template { - match *t { - TComp(ref parent_ci) => parent_ci.borrow_mut().has_destructor = true, - _ => {} - } - } - } - CXCursor_NonTypeTemplateParameter => { - log_err_warn(ctx, &format!("warning: Non-type template parameter in composite member could affect layout: `{}` (kind {}) in `{}` ({})", - cursor.spelling(), cursor.kind(), parent.spelling(), - cursor.location()), false); - ci.has_non_type_template_params = true; - } - CXCursor_VarDecl => { - if !ctx.options.class_constants { - return CXChildVisit_Continue; - } - - let linkage = cursor.linkage(); - if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { - return CXChildVisit_Continue; - } - - let visibility = cursor.visibility(); - if visibility != CXVisibility_Default { - return CXChildVisit_Continue; - } - - let var = decl_name(ctx, cursor); - ci.vars.push(var); - } - // Intentionally not handled - CXCursor_CXXAccessSpecifier | - CXCursor_CXXFinalAttr | - CXCursor_Constructor | - CXCursor_FunctionTemplate | - CXCursor_ConversionFunction => {} - _ => { - // XXX: Some kind of warning would be nice, but this produces far - // too many. - log_err_warn(ctx, &format!("unhandled composite member `{}` (kind {}) in `{}` ({})", - cursor.spelling(), cursor.kind(), parent.spelling(), - cursor.location()), false); - } - } - CXChildVisit_Continue -} - -fn visit_enum(cursor: &Cursor, - items: &mut Vec<EnumItem>) -> Enum_CXVisitorResult { - if cursor.kind() == CXCursor_EnumConstantDecl { - let name = cursor.spelling(); - let comment = cursor.raw_comment(); - let val = cursor.enum_val(); - let item = EnumItem::new(name, comment, val); - items.push(item); - } - CXChildVisit_Continue -} - -fn parse_int_literal_tokens(cursor: &Cursor, unit: &TranslationUnit, which: usize) -> Option<i64> { - match unit.tokens(cursor) { - None => None, - Some(tokens) => { - if tokens.len() <= which || tokens[which].kind != CXToken_Literal { - None - } else { - let ref s = tokens[which].spelling; - let parsed = { - //TODO: try to preserve hex literals? - if s.starts_with("0x") { - i64::from_str_radix(&s[2..], 16) - } else { - s.parse() - } - }; - match parsed { - Ok(i) => Some(i), - Err(_) => None, - } - } - } - } -} - -fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option<i64> { - if cursor.kind() == CXCursor_IntegerLiteral { - return parse_int_literal_tokens(cursor, unit, 0); - } - return None; -} - -fn visit_top(cursor: &Cursor, - mut ctx: &mut ClangParserCtx) -> Enum_CXVisitorResult { - if !match_pattern(ctx, cursor) { - return CXChildVisit_Continue; - } - - match cursor.kind() { - CXCursor_UnexposedDecl => { - return CXChildVisit_Recurse; - } - CXCursor_StructDecl - | CXCursor_UnionDecl - | CXCursor_ClassDecl - | CXCursor_ClassTemplate => { - let anno = Annotations::new(cursor); - fwd_decl(ctx, cursor, move |ctx_| { - let decl = decl_name(ctx_, cursor); - let ci = decl.compinfo(); - // This clear() is needed because of the speculation we do - // on incomplete types inside visit_composite() members. - ci.borrow_mut().args.clear(); - cursor.visit(|c, p| { - let mut ci_ = ci.borrow_mut(); - visit_composite(c, p, ctx_, &mut ci_) - }); - - if anno.opaque { - ci.borrow_mut().opaque = true; - } - - if anno.hide { - ci.borrow_mut().hide = true; - } - - if anno.no_copy { - ci.borrow_mut().no_copy = true; - } - - // If we find a previous translation, we take it now and carry - // on. - // - // XXX: This clone is spurious and could be avoided with another - // scope I think. - let name = ci.borrow().name.clone(); - if let Some(translation) = ctx_.current_module_mut().translations.remove(&name) { - println!("*** {}: found previous translation", name); - if let GComp(ref translated) = translation { - *ci.borrow_mut() = translated.borrow().clone(); - } - } - - if let Some(other_type_name) = anno.use_as { - ci.borrow_mut().name = other_type_name.clone(); - // if the translated type already existed, and we can - // replace it, just do it (tm). - // - // We'll still need the translations map for not found - // translations and stuff like that. - // - // This is a linear search, which is crap, but fwiw it's not - // too common (just when a type marked as translation is - // found). - // - // NB: We have to also loop through the `name` map to take - // declarations in files that haven't been matched into - // account (since they won't appear in globals). - let mut found_in_globals = false; - for v in ctx_.current_module_mut().globals.iter_mut() { - match *v { - GComp(ref mut other_ci) => { - if other_ci.borrow().name == other_type_name { - *other_ci.borrow_mut() = ci.borrow().clone(); - found_in_globals = true; - } - }, - _ => {}, - } - } - - for (cursor, v) in ctx_.name.iter_mut() { - // We can find ourselves here, and that's no fun at - // all. - if *cursor == ci.borrow().parser_cursor.unwrap() { - continue; - } - match *v { - GComp(ref mut other_ci) | - GCompDecl(ref mut other_ci) => { - if other_ci.borrow().name == other_type_name { - // We have to preserve template parameter - // names here if we want to survive. - let args = other_ci.borrow().args.clone(); - *other_ci.borrow_mut() = ci.borrow().clone(); - other_ci.borrow_mut().args = args; - } - } - _ => {} - } - } - - if !found_in_globals { - ctx_.current_module_mut().translations - .insert(other_type_name, GComp(ci)); - } - } else { - ctx_.current_module_mut().globals.push(GComp(ci)); - } - }); - CXChildVisit_Continue - } - CXCursor_EnumDecl => { - fwd_decl(ctx, cursor, |ctx_| { - let decl = decl_name(ctx_, cursor); - let ei = decl.enuminfo(); - ei.borrow_mut().comment = cursor.raw_comment(); - cursor.visit(|c, _: &Cursor| { - let mut ei_ = ei.borrow_mut(); - visit_enum(c, &mut ei_.items) - }); - ctx_.current_module_mut().globals.push(GEnum(ei)); - }); - CXChildVisit_Continue - } - CXCursor_FunctionDecl => { - if ctx.options.ignore_functions { - return CXChildVisit_Continue; - } - - let linkage = cursor.linkage(); - if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { - return CXChildVisit_Continue; - } - - let visibility = cursor.visibility(); - if visibility != CXVisibility_Default { - return CXChildVisit_Continue; - } - - if cursor.is_inlined_function() { - return CXChildVisit_Continue; - } - - let spelling = cursor.spelling(); - if spelling.len() > 8 && - &(spelling)[..8] == "operator" { - return CXChildVisit_Continue; - } - - let func = decl_name(ctx, cursor); - let vi = func.varinfo(); - let mut vi = vi.borrow_mut(); - - vi.ty = TFuncPtr(mk_fn_sig(ctx, &cursor.cur_type(), cursor)); - ctx.current_module_mut().globals.push(func); - - CXChildVisit_Continue - } - CXCursor_VarDecl => { - // TODO: At some point we might want to mangle them instead? - // We already have a bunch of that logic. - if !ctx.in_root_namespace() && !ctx.options.namespaced_constants { - return CXChildVisit_Continue; - } - - let linkage = cursor.linkage(); - if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { - return CXChildVisit_Continue; - } - - let visibility = cursor.visibility(); - if visibility != CXVisibility_Default { - return CXChildVisit_Continue; - } - let val = decl_name(ctx, cursor); - ctx.current_module_mut().globals.push(val); - - CXChildVisit_Continue - } - CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => { - let anno = Annotations::new(cursor); - if anno.hide { - return CXChildVisit_Continue; - } - - let mut under_ty = cursor.typedef_type(); - if under_ty.kind() == CXType_Unexposed { - under_ty = under_ty.canonical_type(); - } - - if cursor.spelling() == - cursor.typedef_type().declaration().spelling() { - // XXX: This is a real hack, but in the common idiom of: - // typedef struct xxx { ... } xxx; - // - // The annotation arrives here, so... - if anno.opaque { - ctx.options.opaque_types.push(cursor.spelling()); - } - return CXChildVisit_Continue; - } - let ty = conv_ty(ctx, &under_ty, cursor); - let typedef = decl_name(ctx, cursor); - let ti = typedef.typeinfo(); - let mut ti = ti.borrow_mut(); - ti.ty = ty.clone(); - - if anno.opaque { - ti.opaque = true; - } - - ti.comment = cursor.raw_comment(); - ctx.current_module_mut().globals.push(typedef); - - opaque_ty(ctx, &under_ty); - - CXChildVisit_Continue - } - CXCursor_FieldDecl => { - CXChildVisit_Continue - } - CXCursor_Namespace => { - if !ctx.options.enable_cxx_namespaces { - ctx.namespace_depth += 1; - cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx)); - ctx.namespace_depth -= 1; - return CXChildVisit_Continue; - } - - let namespace_name = match ctx.current_translation_unit.tokens(cursor) { - None => None, - Some(tokens) => { - if tokens.len() <= 1 { - None - } else { - match &*tokens[1].spelling { - "{" => None, - s => Some(s.to_owned()), - } - } - } - }.unwrap_or_else(|| { - ctx.anonymous_modules_found += 1; - format!("__anonymous{}", ctx.anonymous_modules_found) - }); - - // Find an existing namespace children of the current one - let mod_id = ctx.current_module() - .children_ids.iter() - .find(|id| ctx.module_map.get(id).unwrap().name == namespace_name) - .map(|id| *id); - - let mod_id = match mod_id { - Some(id) => id, - None => { - let parent_id = ctx.current_module_id; - let id = ModuleId::next(); - ctx.module_map.get_mut(&parent_id).unwrap().children_ids.push(id); - ctx.module_map.insert(id, Module::new(namespace_name, Some(parent_id))); - id - } - }; - - let previous_id = ctx.current_module_id; - - ctx.current_module_id = mod_id; - ctx.namespace_depth += 1; - cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx)); - ctx.namespace_depth -= 1; - ctx.current_module_id = previous_id; - - return CXChildVisit_Continue; - } - CXCursor_MacroDefinition => { - let val = parse_int_literal_tokens(cursor, &ctx.current_translation_unit, 1); - let val = match val { - None => return CXChildVisit_Continue, // Not an integer literal. - Some(v) => v, - }; - let var = decl_name(ctx, cursor); - let vi = var.varinfo(); - let mut vi = vi.borrow_mut(); - vi.ty = if val.abs() > u32::max_value() as i64 { - TInt(IULongLong, Layout::new(8, 8)) - } else { - TInt(IUInt, Layout::new(4, 4)) - }; - vi.is_const = true; - vi.val = Some(val); - ctx.current_module_mut().globals.push(var); - - return CXChildVisit_Continue; - } - _ => { - // println!("Not handled cursor: {}", cursor.kind()); - return CXChildVisit_Continue; - } - } -} - -fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) { - if is_err { - ctx.err_count += 1; - ctx.logger.error(msg); - } else { - ctx.logger.warn(msg); - } -} - -pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<ModuleMap, ()> { - let ix = cx::Index::create(false, true); - if ix.is_null() { - logger.error("Clang failed to create index"); - return Err(()) - } - - let unit = TranslationUnit::parse(&ix, "", &options.clang_args, &[], CXTranslationUnit_DetailedPreprocessingRecord); - if unit.is_null() { - logger.error("No input files given"); - return Err(()) - } - - let mut ctx = ClangParserCtx { - options: options, - name: HashMap::new(), - builtin_defs: vec!(), - module_map: ModuleMap::new(), - namespace_depth: 0, - current_module_id: ROOT_MODULE_ID, - current_translation_unit: unit, - logger: logger, - err_count: 0, - anonymous_modules_found: 0, - }; - - ctx.module_map.insert(ROOT_MODULE_ID, Module::new("root".to_owned(), None)); - - let diags = ctx.current_translation_unit.diags(); - for d in &diags { - let msg = d.format(Diagnostic::default_opts()); - let is_err = d.severity() >= CXDiagnostic_Error; - log_err_warn(&mut ctx, &msg, is_err); - } - - if ctx.err_count > 0 { - logger.error(&format!("{} errors after diagnostics", ctx.err_count)); - return Err(()) - } - - let cursor = ctx.current_translation_unit.cursor(); - - if ctx.options.emit_ast { - cursor.visit(|cur, _: &Cursor| ast_dump(cur, 0)); - } - - cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx)); - - while !ctx.builtin_defs.is_empty() { - let c = ctx.builtin_defs.remove(0); - visit_top(&c.definition(), &mut ctx); - } - - ctx.current_translation_unit.dispose(); - ix.dispose(); - - if ctx.err_count > 0 { - logger.error(&format!("{} errors after translation", ctx.err_count)); - return Err(()) - } - - Ok(ctx.module_map) -} |