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