1 use crate::syntax::namespace::Namespace; 2 use quote::quote; 3 use syn::parse::{Error, Parse, ParseStream, Result}; 4 use syn::{ 5 braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemImpl, 6 ItemStruct, ItemUse, LitStr, Token, Visibility, 7 }; 8 9 pub struct Module { 10 pub namespace: Namespace, 11 pub attrs: Vec<Attribute>, 12 pub vis: Visibility, 13 pub unsafety: Option<Token![unsafe]>, 14 pub mod_token: Token![mod], 15 pub ident: Ident, 16 pub brace_token: token::Brace, 17 pub content: Vec<Item>, 18 } 19 20 pub enum Item { 21 Struct(ItemStruct), 22 Enum(ItemEnum), 23 ForeignMod(ItemForeignMod), 24 Use(ItemUse), 25 Impl(ItemImpl), 26 Other(RustItem), 27 } 28 29 pub struct ItemForeignMod { 30 pub attrs: Vec<Attribute>, 31 pub unsafety: Option<Token![unsafe]>, 32 pub abi: Abi, 33 pub brace_token: token::Brace, 34 pub items: Vec<ForeignItem>, 35 } 36 37 impl Parse for Module { parse(input: ParseStream) -> Result<Self>38 fn parse(input: ParseStream) -> Result<Self> { 39 let namespace = Namespace::ROOT; 40 let mut attrs = input.call(Attribute::parse_outer)?; 41 let vis: Visibility = input.parse()?; 42 let unsafety: Option<Token![unsafe]> = input.parse()?; 43 let mod_token: Token![mod] = input.parse()?; 44 let ident: Ident = input.parse()?; 45 46 let semi: Option<Token![;]> = input.parse()?; 47 if let Some(semi) = semi { 48 let span = quote!(#vis #mod_token #semi); 49 return Err(Error::new_spanned( 50 span, 51 "#[cxx::bridge] module must have inline contents", 52 )); 53 } 54 55 let content; 56 let brace_token = braced!(content in input); 57 attrs.extend(content.call(Attribute::parse_inner)?); 58 59 let mut items = Vec::new(); 60 while !content.is_empty() { 61 items.push(content.parse()?); 62 } 63 64 Ok(Module { 65 namespace, 66 attrs, 67 vis, 68 unsafety, 69 mod_token, 70 ident, 71 brace_token, 72 content: items, 73 }) 74 } 75 } 76 77 impl Parse for Item { parse(input: ParseStream) -> Result<Self>78 fn parse(input: ParseStream) -> Result<Self> { 79 let attrs = input.call(Attribute::parse_outer)?; 80 81 let ahead = input.fork(); 82 let unsafety = if ahead.parse::<Option<Token![unsafe]>>()?.is_some() 83 && ahead.parse::<Option<Token![extern]>>()?.is_some() 84 && ahead.parse::<Option<LitStr>>().is_ok() 85 && ahead.peek(token::Brace) 86 { 87 Some(input.parse()?) 88 } else { 89 None 90 }; 91 92 let item = input.parse()?; 93 match item { 94 RustItem::Struct(item) => Ok(Item::Struct(ItemStruct { attrs, ..item })), 95 RustItem::Enum(item) => Ok(Item::Enum(ItemEnum { attrs, ..item })), 96 RustItem::ForeignMod(item) => Ok(Item::ForeignMod(ItemForeignMod { 97 attrs, 98 unsafety, 99 abi: item.abi, 100 brace_token: item.brace_token, 101 items: item.items, 102 })), 103 RustItem::Impl(item) => Ok(Item::Impl(ItemImpl { attrs, ..item })), 104 RustItem::Use(item) => Ok(Item::Use(ItemUse { attrs, ..item })), 105 other => Ok(Item::Other(other)), 106 } 107 } 108 } 109