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