blob: 25af2296c4ac263be948f2bcc70ff675297e638f [file] [log] [blame]
Adrian Taylorc8713432020-10-21 18:20:55 -07001use crate::syntax::namespace::Namespace;
David Tolnay3e628882020-05-10 15:30:14 -07002use crate::syntax::report::Errors;
David Tolnayddf69e22020-05-10 22:08:20 -07003use crate::syntax::Atom::{self, *};
David Tolnay7db73692019-10-20 14:51:12 -04004use crate::syntax::{Derive, Doc};
David Tolnayddf69e22020-05-10 22:08:20 -07005use proc_macro2::Ident;
David Tolnayb129ea72020-05-10 14:29:30 -07006use syn::parse::{ParseStream, Parser as _};
David Tolnay7db73692019-10-20 14:51:12 -04007use syn::{Attribute, Error, LitStr, Path, Result, Token};
8
David Tolnayb129ea72020-05-10 14:29:30 -07009#[derive(Default)]
10pub struct Parser<'a> {
11 pub doc: Option<&'a mut Doc>,
12 pub derives: Option<&'a mut Vec<Derive>>,
David Tolnayddf69e22020-05-10 22:08:20 -070013 pub repr: Option<&'a mut Option<Atom>>,
David Tolnay1039a242020-10-09 19:18:12 -070014 pub cxx_name: Option<&'a mut Option<Ident>>,
15 pub rust_name: Option<&'a mut Option<Ident>>,
Adrian Taylorc8713432020-10-21 18:20:55 -070016 pub namespace: Option<&'a mut Namespace>,
David Tolnay7db73692019-10-20 14:51:12 -040017}
18
David Tolnay3e628882020-05-10 15:30:14 -070019pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) {
David Tolnay7db73692019-10-20 14:51:12 -040020 for attr in attrs {
21 if attr.path.is_ident("doc") {
David Tolnay3e628882020-05-10 15:30:14 -070022 match parse_doc_attribute.parse2(attr.tokens.clone()) {
23 Ok(lit) => {
24 if let Some(doc) = &mut parser.doc {
25 doc.push(lit);
26 continue;
27 }
28 }
29 Err(err) => return cx.push(err),
David Tolnayb129ea72020-05-10 14:29:30 -070030 }
David Tolnay7db73692019-10-20 14:51:12 -040031 } else if attr.path.is_ident("derive") {
David Tolnay3e628882020-05-10 15:30:14 -070032 match attr.parse_args_with(parse_derive_attribute) {
33 Ok(attr) => {
34 if let Some(derives) = &mut parser.derives {
35 derives.extend(attr);
36 continue;
37 }
38 }
39 Err(err) => return cx.push(err),
David Tolnay7db73692019-10-20 14:51:12 -040040 }
David Tolnayddf69e22020-05-10 22:08:20 -070041 } else if attr.path.is_ident("repr") {
42 match attr.parse_args_with(parse_repr_attribute) {
43 Ok(attr) => {
44 if let Some(repr) = &mut parser.repr {
45 **repr = Some(attr);
46 continue;
47 }
48 }
49 Err(err) => return cx.push(err),
50 }
David Tolnay1039a242020-10-09 19:18:12 -070051 } else if attr.path.is_ident("cxx_name") {
52 match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
53 Ok(attr) => {
54 if let Some(cxx_name) = &mut parser.cxx_name {
55 **cxx_name = Some(attr);
56 continue;
57 }
58 }
59 Err(err) => return cx.push(err),
60 }
61 } else if attr.path.is_ident("rust_name") {
62 match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
63 Ok(attr) => {
64 if let Some(rust_name) = &mut parser.rust_name {
65 **rust_name = Some(attr);
66 continue;
67 }
68 }
69 Err(err) => return cx.push(err),
70 }
Adrian Taylorc8713432020-10-21 18:20:55 -070071 } else if attr.path.is_ident("namespace") {
72 match parse_namespace_attribute.parse2(attr.tokens.clone()) {
73 Ok(attr) => {
74 if let Some(namespace) = &mut parser.namespace {
75 **namespace = attr;
76 continue;
77 }
78 }
79 Err(err) => return cx.push(err),
80 }
David Tolnay7db73692019-10-20 14:51:12 -040081 }
David Tolnay3e628882020-05-10 15:30:14 -070082 return cx.error(attr, "unsupported attribute");
David Tolnay7db73692019-10-20 14:51:12 -040083 }
David Tolnay7db73692019-10-20 14:51:12 -040084}
85
86fn parse_doc_attribute(input: ParseStream) -> Result<LitStr> {
87 input.parse::<Token![=]>()?;
88 let lit: LitStr = input.parse()?;
89 Ok(lit)
90}
91
David Tolnaye86b9cf2020-05-10 14:24:29 -070092fn parse_derive_attribute(input: ParseStream) -> Result<Vec<Derive>> {
David Tolnay7db73692019-10-20 14:51:12 -040093 input
94 .parse_terminated::<Path, Token![,]>(Path::parse_mod_style)?
95 .into_iter()
David Tolnaye86b9cf2020-05-10 14:24:29 -070096 .map(|path| {
97 if let Some(ident) = path.get_ident() {
98 if let Some(derive) = Derive::from(ident) {
99 return Ok(derive);
100 }
101 }
102 Err(Error::new_spanned(path, "unsupported derive"))
David Tolnay7db73692019-10-20 14:51:12 -0400103 })
104 .collect()
105}
David Tolnayddf69e22020-05-10 22:08:20 -0700106
107fn parse_repr_attribute(input: ParseStream) -> Result<Atom> {
108 let begin = input.cursor();
109 let ident: Ident = input.parse()?;
110 if let Some(atom) = Atom::from(&ident) {
111 match atom {
David Tolnay8155e582020-05-11 00:05:02 -0700112 U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize if input.is_empty() => {
113 return Ok(atom);
114 }
David Tolnayddf69e22020-05-10 22:08:20 -0700115 _ => {}
116 }
117 }
118 Err(Error::new_spanned(
119 begin.token_stream(),
120 "unrecognized repr",
121 ))
122}
David Tolnay1039a242020-10-09 19:18:12 -0700123
124fn parse_function_alias_attribute(input: ParseStream) -> Result<Ident> {
125 input.parse::<Token![=]>()?;
126 if input.peek(LitStr) {
127 let lit: LitStr = input.parse()?;
128 lit.parse()
129 } else {
130 input.parse()
131 }
132}
Adrian Taylorc8713432020-10-21 18:20:55 -0700133
134fn parse_namespace_attribute(input: ParseStream) -> Result<Namespace> {
135 let content;
136 syn::parenthesized!(content in input);
137 let namespace = content.parse::<Namespace>()?;
138 Ok(namespace)
139}