blob: c69640711831bda286239eb8a9dd35f7c9f3d7ac [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();
David Tolnay02550c02020-08-29 15:20:50 -070024 let mut attrs = input.call(Attribute::parse_outer)?;
David Tolnay3c64a4e2020-08-29 14:07:38 -070025 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;
David Tolnay02550c02020-08-29 15:20:50 -070048 attrs.extend(module.attrs);
David Tolnay3c64a4e2020-08-29 14:07:38 -070049 module.attrs = attrs;
50 modules.push(module);
51 } else {
52 input.advance_to(&ahead);
53 input.parse::<Token![mod]>()?;
54 input.parse::<Ident>()?;
55 let semi: Option<Token![;]> = input.parse()?;
56 if semi.is_none() {
57 let content;
58 braced!(content in input);
59 parse(&content, modules)?;
60 }
61 }
62 }
63 Ok(())
64}
65
66fn parse_args(attr: &Attribute) -> Result<Namespace> {
67 if attr.tokens.is_empty() {
68 Ok(Namespace::none())
69 } else {
70 attr.parse_args()
David Tolnayfcd8f462020-08-29 12:13:09 -070071 }
72}