blob: 2141c1746da0d348dfe99b64ca21963780d0fcd9 [file] [log] [blame]
David Tolnay3c64a4e2020-08-29 14:07:38 -07001use crate::syntax::namespace::Namespace;
2use quote::quote;
David Tolnay05ef6ff2020-08-29 11:27:05 -07003use syn::parse::{Error, Parse, ParseStream, Result};
David Tolnay00a83852020-08-29 15:06:16 -07004use syn::{
David Tolnayc598a272020-08-29 15:10:18 -07005 braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemStruct,
David Tolnay0c0cfee2020-08-29 15:29:25 -07006 ItemUse, LitStr, Token, Visibility,
David Tolnay00a83852020-08-29 15:06:16 -07007};
David Tolnay05ef6ff2020-08-29 11:27:05 -07008
9pub struct Module {
David Tolnay3c64a4e2020-08-29 14:07:38 -070010 pub namespace: Namespace,
David Tolnay05ef6ff2020-08-29 11:27:05 -070011 pub attrs: Vec<Attribute>,
12 pub vis: Visibility,
David Tolnay633f5662020-08-29 14:47:45 -070013 pub unsafety: Option<Token![unsafe]>,
David Tolnay05ef6ff2020-08-29 11:27:05 -070014 pub mod_token: Token![mod],
15 pub ident: Ident,
16 pub brace_token: token::Brace,
17 pub content: Vec<Item>,
18}
19
David Tolnay00a83852020-08-29 15:06:16 -070020pub enum Item {
21 Struct(ItemStruct),
22 Enum(ItemEnum),
23 ForeignMod(ItemForeignMod),
24 Use(ItemUse),
25 Other(RustItem),
26}
27
David Tolnayc598a272020-08-29 15:10:18 -070028pub struct ItemForeignMod {
29 pub attrs: Vec<Attribute>,
30 pub unsafety: Option<Token![unsafe]>,
31 pub abi: Abi,
32 pub brace_token: token::Brace,
33 pub items: Vec<ForeignItem>,
34}
35
David Tolnay05ef6ff2020-08-29 11:27:05 -070036impl Parse for Module {
37 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay3c64a4e2020-08-29 14:07:38 -070038 let namespace = Namespace::none();
David Tolnay05ef6ff2020-08-29 11:27:05 -070039 let mut attrs = input.call(Attribute::parse_outer)?;
40 let vis: Visibility = input.parse()?;
David Tolnay633f5662020-08-29 14:47:45 -070041 let unsafety: Option<Token![unsafe]> = input.parse()?;
David Tolnay05ef6ff2020-08-29 11:27:05 -070042 let mod_token: Token![mod] = input.parse()?;
43 let ident: Ident = input.parse()?;
44
David Tolnay3c64a4e2020-08-29 14:07:38 -070045 let semi: Option<Token![;]> = input.parse()?;
46 if let Some(semi) = semi {
47 let span = quote!(#vis #mod_token #semi);
48 return Err(Error::new_spanned(
49 span,
David Tolnay05ef6ff2020-08-29 11:27:05 -070050 "#[cxx::bridge] module must have inline contents",
51 ))?;
52 }
53
54 let content;
55 let brace_token = braced!(content in input);
56 attrs.extend(content.call(Attribute::parse_inner)?);
57
58 let mut items = Vec::new();
59 while !content.is_empty() {
60 items.push(content.parse()?);
61 }
62
63 Ok(Module {
David Tolnay3c64a4e2020-08-29 14:07:38 -070064 namespace,
David Tolnay05ef6ff2020-08-29 11:27:05 -070065 attrs,
66 vis,
David Tolnay633f5662020-08-29 14:47:45 -070067 unsafety,
David Tolnay05ef6ff2020-08-29 11:27:05 -070068 mod_token,
69 ident,
70 brace_token,
71 content: items,
72 })
73 }
74}
David Tolnay00a83852020-08-29 15:06:16 -070075
76impl Parse for Item {
77 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay0c0cfee2020-08-29 15:29:25 -070078 let attrs = input.call(Attribute::parse_outer)?;
79
80 let ahead = input.fork();
81 let unsafety = if ahead.parse::<Option<Token![unsafe]>>()?.is_some()
82 && ahead.parse::<Option<Token![extern]>>()?.is_some()
83 && ahead.parse::<Option<LitStr>>().is_ok()
84 && ahead.peek(token::Brace)
85 {
86 Some(input.parse()?)
87 } else {
88 None
89 };
90
David Tolnay00a83852020-08-29 15:06:16 -070091 let item = input.parse()?;
92 match item {
David Tolnay0c0cfee2020-08-29 15:29:25 -070093 RustItem::Struct(item) => Ok(Item::Struct(ItemStruct { attrs, ..item })),
94 RustItem::Enum(item) => Ok(Item::Enum(ItemEnum { attrs, ..item })),
David Tolnayc598a272020-08-29 15:10:18 -070095 RustItem::ForeignMod(item) => Ok(Item::ForeignMod(ItemForeignMod {
96 attrs: item.attrs,
David Tolnay0c0cfee2020-08-29 15:29:25 -070097 unsafety,
David Tolnayc598a272020-08-29 15:10:18 -070098 abi: item.abi,
99 brace_token: item.brace_token,
100 items: item.items,
101 })),
David Tolnay0c0cfee2020-08-29 15:29:25 -0700102 RustItem::Use(item) => Ok(Item::Use(ItemUse { attrs, ..item })),
David Tolnay00a83852020-08-29 15:06:16 -0700103 other => Ok(Item::Other(other)),
104 }
105 }
106}