• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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