blob: a2f86e69b352c0519e5e7edbfdcdd5e86d7a9100 [file] [log] [blame]
David Tolnay3c64a4e2020-08-29 14:07:38 -07001use crate::syntax::file::Module;
2use crate::syntax::namespace::Namespace;
3use syn::parse::discouraged::Speculative;
4use syn::parse::{Error, Parse, ParseStream, Result};
5use syn::{braced, Attribute, Ident, Item, Token, Visibility};
David Tolnayfcd8f462020-08-29 12:13:09 -07006
7pub struct File {
David Tolnay3c64a4e2020-08-29 14:07:38 -07008 pub modules: Vec<Module>,
David Tolnayfcd8f462020-08-29 12:13:09 -07009}
10
11impl Parse for File {
12 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay3c64a4e2020-08-29 14:07:38 -070013 let mut modules = Vec::new();
14 input.call(Attribute::parse_inner)?;
15 parse(input, &mut modules)?;
16 Ok(File { modules })
17 }
18}
David Tolnayfcd8f462020-08-29 12:13:09 -070019
David Tolnay3c64a4e2020-08-29 14:07:38 -070020fn parse(input: ParseStream, modules: &mut Vec<Module>) -> Result<()> {
21 while !input.is_empty() {
22 let mut cxx_bridge = false;
23 let mut namespace = Namespace::none();
24 let attrs = input.call(Attribute::parse_outer)?;
25 for attr in &attrs {
26 let path = &attr.path.segments;
27 if path.len() == 2 && path[0].ident == "cxx" && path[1].ident == "bridge" {
28 cxx_bridge = true;
29 namespace = parse_args(attr)?;
30 break;
31 }
David Tolnayfcd8f462020-08-29 12:13:09 -070032 }
33
David Tolnay3c64a4e2020-08-29 14:07:38 -070034 let ahead = input.fork();
35 ahead.parse::<Visibility>()?;
36 ahead.parse::<Option<Token![unsafe]>>()?;
37 if !ahead.peek(Token![mod]) {
38 let item: Item = input.parse()?;
39 if cxx_bridge {
40 return Err(Error::new_spanned(item, "expected a module"));
41 }
42 continue;
43 }
44
45 if cxx_bridge {
46 let mut module: Module = input.parse()?;
47 module.namespace = namespace;
48 module.attrs = attrs;
49 modules.push(module);
50 } else {
51 input.advance_to(&ahead);
52 input.parse::<Token![mod]>()?;
53 input.parse::<Ident>()?;
54 let semi: Option<Token![;]> = input.parse()?;
55 if semi.is_none() {
56 let content;
57 braced!(content in input);
58 parse(&content, modules)?;
59 }
60 }
61 }
62 Ok(())
63}
64
65fn parse_args(attr: &Attribute) -> Result<Namespace> {
66 if attr.tokens.is_empty() {
67 Ok(Namespace::none())
68 } else {
69 attr.parse_args()
David Tolnayfcd8f462020-08-29 12:13:09 -070070 }
71}