blob: 18e92e230f73c88f0fdcdda3ac461ae53603c628 [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 Tolnaya2dfcbf2020-12-21 15:46:24 -080014 pub namespace: Option<&'a mut Namespace>,
David Tolnay1039a242020-10-09 19:18:12 -070015 pub cxx_name: Option<&'a mut Option<Ident>>,
16 pub rust_name: Option<&'a mut Option<Ident>>,
David Tolnayd25033c2020-12-21 16:24:19 -080017
18 // Suppress clippy needless_update lint ("struct update has no effect, all
19 // the fields in the struct have already been specified") when preemptively
20 // writing `..Default::default()`.
21 pub(crate) _more: (),
David Tolnay7db73692019-10-20 14:51:12 -040022}
23
David Tolnay3e628882020-05-10 15:30:14 -070024pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) {
David Tolnay7db73692019-10-20 14:51:12 -040025 for attr in attrs {
26 if attr.path.is_ident("doc") {
David Tolnay3e628882020-05-10 15:30:14 -070027 match parse_doc_attribute.parse2(attr.tokens.clone()) {
28 Ok(lit) => {
29 if let Some(doc) = &mut parser.doc {
30 doc.push(lit);
31 continue;
32 }
33 }
34 Err(err) => return cx.push(err),
David Tolnayb129ea72020-05-10 14:29:30 -070035 }
David Tolnay7db73692019-10-20 14:51:12 -040036 } else if attr.path.is_ident("derive") {
David Tolnayf4b93342020-11-27 13:59:42 -080037 match attr.parse_args_with(|attr: ParseStream| parse_derive_attribute(cx, attr)) {
David Tolnay3e628882020-05-10 15:30:14 -070038 Ok(attr) => {
39 if let Some(derives) = &mut parser.derives {
40 derives.extend(attr);
41 continue;
42 }
43 }
44 Err(err) => return cx.push(err),
David Tolnay7db73692019-10-20 14:51:12 -040045 }
David Tolnayddf69e22020-05-10 22:08:20 -070046 } else if attr.path.is_ident("repr") {
47 match attr.parse_args_with(parse_repr_attribute) {
48 Ok(attr) => {
49 if let Some(repr) = &mut parser.repr {
50 **repr = Some(attr);
51 continue;
52 }
53 }
54 Err(err) => return cx.push(err),
55 }
David Tolnaya2dfcbf2020-12-21 15:46:24 -080056 } else if attr.path.is_ident("namespace") {
57 match parse_namespace_attribute.parse2(attr.tokens.clone()) {
58 Ok(attr) => {
59 if let Some(namespace) = &mut parser.namespace {
60 **namespace = attr;
61 continue;
62 }
63 }
64 Err(err) => return cx.push(err),
65 }
David Tolnay1039a242020-10-09 19:18:12 -070066 } else if attr.path.is_ident("cxx_name") {
67 match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
68 Ok(attr) => {
69 if let Some(cxx_name) = &mut parser.cxx_name {
70 **cxx_name = Some(attr);
71 continue;
72 }
73 }
74 Err(err) => return cx.push(err),
75 }
76 } else if attr.path.is_ident("rust_name") {
77 match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
78 Ok(attr) => {
79 if let Some(rust_name) = &mut parser.rust_name {
80 **rust_name = Some(attr);
81 continue;
82 }
83 }
84 Err(err) => return cx.push(err),
85 }
David Tolnay7db73692019-10-20 14:51:12 -040086 }
David Tolnay3e628882020-05-10 15:30:14 -070087 return cx.error(attr, "unsupported attribute");
David Tolnay7db73692019-10-20 14:51:12 -040088 }
David Tolnay7db73692019-10-20 14:51:12 -040089}
90
91fn parse_doc_attribute(input: ParseStream) -> Result<LitStr> {
92 input.parse::<Token![=]>()?;
93 let lit: LitStr = input.parse()?;
94 Ok(lit)
95}
96
David Tolnayf4b93342020-11-27 13:59:42 -080097fn parse_derive_attribute(cx: &mut Errors, input: ParseStream) -> Result<Vec<Derive>> {
98 let paths = input.parse_terminated::<Path, Token![,]>(Path::parse_mod_style)?;
99
100 let mut derives = Vec::new();
101 for path in paths {
102 if let Some(ident) = path.get_ident() {
103 if let Some(derive) = Derive::from(ident) {
104 derives.push(derive);
105 continue;
David Tolnaye86b9cf2020-05-10 14:24:29 -0700106 }
David Tolnayf4b93342020-11-27 13:59:42 -0800107 }
108 cx.error(path, "unsupported derive");
109 }
110 Ok(derives)
David Tolnay7db73692019-10-20 14:51:12 -0400111}
David Tolnayddf69e22020-05-10 22:08:20 -0700112
113fn parse_repr_attribute(input: ParseStream) -> Result<Atom> {
114 let begin = input.cursor();
115 let ident: Ident = input.parse()?;
116 if let Some(atom) = Atom::from(&ident) {
117 match atom {
David Tolnay8155e582020-05-11 00:05:02 -0700118 U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize if input.is_empty() => {
119 return Ok(atom);
120 }
David Tolnayddf69e22020-05-10 22:08:20 -0700121 _ => {}
122 }
123 }
124 Err(Error::new_spanned(
125 begin.token_stream(),
126 "unrecognized repr",
127 ))
128}
David Tolnay1039a242020-10-09 19:18:12 -0700129
David Tolnaya2dfcbf2020-12-21 15:46:24 -0800130fn parse_namespace_attribute(input: ParseStream) -> Result<Namespace> {
131 input.parse::<Token![=]>()?;
132 let namespace = input.parse::<Namespace>()?;
133 Ok(namespace)
134}
135
David Tolnay1039a242020-10-09 19:18:12 -0700136fn parse_function_alias_attribute(input: ParseStream) -> Result<Ident> {
137 input.parse::<Token![=]>()?;
138 if input.peek(LitStr) {
139 let lit: LitStr = input.parse()?;
140 lit.parse()
141 } else {
142 input.parse()
143 }
144}