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