blob: 4c8a3e5da74007467fa552384997d108f2607413 [file] [log] [blame]
David Tolnay3e628882020-05-10 15:30:14 -07001use crate::syntax::report::Errors;
David Tolnayddf69e22020-05-10 22:08:20 -07002use crate::syntax::Atom::{self, *};
David Tolnay7db73692019-10-20 14:51:12 -04003use crate::syntax::{Derive, Doc};
David Tolnayddf69e22020-05-10 22:08:20 -07004use proc_macro2::Ident;
David Tolnayb129ea72020-05-10 14:29:30 -07005use syn::parse::{ParseStream, Parser as _};
David Tolnay7db73692019-10-20 14:51:12 -04006use syn::{Attribute, Error, LitStr, Path, Result, Token};
7
David Tolnayb129ea72020-05-10 14:29:30 -07008#[derive(Default)]
9pub struct Parser<'a> {
10 pub doc: Option<&'a mut Doc>,
11 pub derives: Option<&'a mut Vec<Derive>>,
David Tolnayddf69e22020-05-10 22:08:20 -070012 pub repr: Option<&'a mut Option<Atom>>,
David Tolnay1039a242020-10-09 19:18:12 -070013 pub cxx_name: Option<&'a mut Option<Ident>>,
14 pub rust_name: Option<&'a mut Option<Ident>>,
David Tolnayb129ea72020-05-10 14:29:30 -070015}
16
David Tolnay3e628882020-05-10 15:30:14 -070017pub(super) fn parse_doc(cx: &mut Errors, attrs: &[Attribute]) -> Doc {
David Tolnay7db73692019-10-20 14:51:12 -040018 let mut doc = Doc::new();
David Tolnayb129ea72020-05-10 14:29:30 -070019 parse(
David Tolnay3e628882020-05-10 15:30:14 -070020 cx,
David Tolnayb129ea72020-05-10 14:29:30 -070021 attrs,
22 Parser {
23 doc: Some(&mut doc),
24 ..Parser::default()
25 },
David Tolnay3e628882020-05-10 15:30:14 -070026 );
27 doc
David Tolnay7db73692019-10-20 14:51:12 -040028}
29
David Tolnay3e628882020-05-10 15:30:14 -070030pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) {
David Tolnay7db73692019-10-20 14:51:12 -040031 for attr in attrs {
32 if attr.path.is_ident("doc") {
David Tolnay3e628882020-05-10 15:30:14 -070033 match parse_doc_attribute.parse2(attr.tokens.clone()) {
34 Ok(lit) => {
35 if let Some(doc) = &mut parser.doc {
36 doc.push(lit);
37 continue;
38 }
39 }
40 Err(err) => return cx.push(err),
David Tolnayb129ea72020-05-10 14:29:30 -070041 }
David Tolnay7db73692019-10-20 14:51:12 -040042 } else if attr.path.is_ident("derive") {
David Tolnay3e628882020-05-10 15:30:14 -070043 match attr.parse_args_with(parse_derive_attribute) {
44 Ok(attr) => {
45 if let Some(derives) = &mut parser.derives {
46 derives.extend(attr);
47 continue;
48 }
49 }
50 Err(err) => return cx.push(err),
David Tolnay7db73692019-10-20 14:51:12 -040051 }
David Tolnayddf69e22020-05-10 22:08:20 -070052 } else if attr.path.is_ident("repr") {
53 match attr.parse_args_with(parse_repr_attribute) {
54 Ok(attr) => {
55 if let Some(repr) = &mut parser.repr {
56 **repr = Some(attr);
57 continue;
58 }
59 }
60 Err(err) => return cx.push(err),
61 }
David Tolnay1039a242020-10-09 19:18:12 -070062 } else if attr.path.is_ident("cxx_name") {
63 match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
64 Ok(attr) => {
65 if let Some(cxx_name) = &mut parser.cxx_name {
66 **cxx_name = Some(attr);
67 continue;
68 }
69 }
70 Err(err) => return cx.push(err),
71 }
72 } else if attr.path.is_ident("rust_name") {
73 match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
74 Ok(attr) => {
75 if let Some(rust_name) = &mut parser.rust_name {
76 **rust_name = Some(attr);
77 continue;
78 }
79 }
80 Err(err) => return cx.push(err),
81 }
David Tolnay7db73692019-10-20 14:51:12 -040082 }
David Tolnay3e628882020-05-10 15:30:14 -070083 return cx.error(attr, "unsupported attribute");
David Tolnay7db73692019-10-20 14:51:12 -040084 }
David Tolnay7db73692019-10-20 14:51:12 -040085}
86
87fn parse_doc_attribute(input: ParseStream) -> Result<LitStr> {
88 input.parse::<Token![=]>()?;
89 let lit: LitStr = input.parse()?;
90 Ok(lit)
91}
92
David Tolnaye86b9cf2020-05-10 14:24:29 -070093fn parse_derive_attribute(input: ParseStream) -> Result<Vec<Derive>> {
David Tolnay7db73692019-10-20 14:51:12 -040094 input
95 .parse_terminated::<Path, Token![,]>(Path::parse_mod_style)?
96 .into_iter()
David Tolnaye86b9cf2020-05-10 14:24:29 -070097 .map(|path| {
98 if let Some(ident) = path.get_ident() {
99 if let Some(derive) = Derive::from(ident) {
100 return Ok(derive);
101 }
102 }
103 Err(Error::new_spanned(path, "unsupported derive"))
David Tolnay7db73692019-10-20 14:51:12 -0400104 })
105 .collect()
106}
David Tolnayddf69e22020-05-10 22:08:20 -0700107
108fn parse_repr_attribute(input: ParseStream) -> Result<Atom> {
109 let begin = input.cursor();
110 let ident: Ident = input.parse()?;
111 if let Some(atom) = Atom::from(&ident) {
112 match atom {
David Tolnay8155e582020-05-11 00:05:02 -0700113 U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize if input.is_empty() => {
114 return Ok(atom);
115 }
David Tolnayddf69e22020-05-10 22:08:20 -0700116 _ => {}
117 }
118 }
119 Err(Error::new_spanned(
120 begin.token_stream(),
121 "unrecognized repr",
122 ))
123}
David Tolnay1039a242020-10-09 19:18:12 -0700124
125fn parse_function_alias_attribute(input: ParseStream) -> Result<Ident> {
126 input.parse::<Token![=]>()?;
127 if input.peek(LitStr) {
128 let lit: LitStr = input.parse()?;
129 lit.parse()
130 } else {
131 input.parse()
132 }
133}