cxx_gen/gen/
file.rs

1use 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, Meta, Token, Visibility};
6
7pub(crate) struct File {
8    pub modules: Vec<Module>,
9}
10
11impl Parse for File {
12    fn parse(input: ParseStream) -> Result<Self> {
13        let mut modules = Vec::new();
14        parse(input, &mut modules)?;
15        Ok(File { modules })
16    }
17}
18
19fn parse(input: ParseStream, modules: &mut Vec<Module>) -> Result<()> {
20    input.call(Attribute::parse_inner)?;
21
22    while !input.is_empty() {
23        let mut cxx_bridge = false;
24        let mut namespace = Namespace::ROOT;
25        let mut attrs = input.call(Attribute::parse_outer)?;
26        for attr in &attrs {
27            let path = &attr.path().segments;
28            if path.len() == 2 && path[0].ident == "cxx" && path[1].ident == "bridge" {
29                cxx_bridge = true;
30                namespace = parse_args(attr)?;
31                break;
32            }
33        }
34
35        let ahead = input.fork();
36        ahead.parse::<Visibility>()?;
37        ahead.parse::<Option<Token![unsafe]>>()?;
38        if !ahead.peek(Token![mod]) {
39            let item: Item = input.parse()?;
40            if cxx_bridge {
41                return Err(Error::new_spanned(item, "expected a module"));
42            }
43            continue;
44        }
45
46        if cxx_bridge {
47            let mut module: Module = input.parse()?;
48            module.namespace = namespace;
49            attrs.extend(module.attrs);
50            module.attrs = attrs;
51            modules.push(module);
52        } else {
53            input.advance_to(&ahead);
54            input.parse::<Token![mod]>()?;
55            input.parse::<Ident>()?;
56            let semi: Option<Token![;]> = input.parse()?;
57            if semi.is_none() {
58                let content;
59                braced!(content in input);
60                parse(&content, modules)?;
61            }
62        }
63    }
64
65    Ok(())
66}
67
68fn parse_args(attr: &Attribute) -> Result<Namespace> {
69    if let Meta::Path(_) = attr.meta {
70        Ok(Namespace::ROOT)
71    } else {
72        attr.parse_args_with(Namespace::parse_bridge_attr_namespace)
73    }
74}