blob: 16541a3f68901a4301ed426d5b98a71cc384b476 [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 Tolnayb129ea72020-05-10 14:29:30 -070013}
14
David Tolnay3e628882020-05-10 15:30:14 -070015pub(super) fn parse_doc(cx: &mut Errors, attrs: &[Attribute]) -> Doc {
David Tolnay7db73692019-10-20 14:51:12 -040016 let mut doc = Doc::new();
David Tolnayb129ea72020-05-10 14:29:30 -070017 parse(
David Tolnay3e628882020-05-10 15:30:14 -070018 cx,
David Tolnayb129ea72020-05-10 14:29:30 -070019 attrs,
20 Parser {
21 doc: Some(&mut doc),
22 ..Parser::default()
23 },
David Tolnay3e628882020-05-10 15:30:14 -070024 );
25 doc
David Tolnay7db73692019-10-20 14:51:12 -040026}
27
David Tolnay3e628882020-05-10 15:30:14 -070028pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) {
David Tolnay7db73692019-10-20 14:51:12 -040029 for attr in attrs {
30 if attr.path.is_ident("doc") {
David Tolnay3e628882020-05-10 15:30:14 -070031 match parse_doc_attribute.parse2(attr.tokens.clone()) {
32 Ok(lit) => {
33 if let Some(doc) = &mut parser.doc {
34 doc.push(lit);
35 continue;
36 }
37 }
38 Err(err) => return cx.push(err),
David Tolnayb129ea72020-05-10 14:29:30 -070039 }
David Tolnay7db73692019-10-20 14:51:12 -040040 } else if attr.path.is_ident("derive") {
David Tolnay3e628882020-05-10 15:30:14 -070041 match attr.parse_args_with(parse_derive_attribute) {
42 Ok(attr) => {
43 if let Some(derives) = &mut parser.derives {
44 derives.extend(attr);
45 continue;
46 }
47 }
48 Err(err) => return cx.push(err),
David Tolnay7db73692019-10-20 14:51:12 -040049 }
David Tolnayddf69e22020-05-10 22:08:20 -070050 } else if attr.path.is_ident("repr") {
51 match attr.parse_args_with(parse_repr_attribute) {
52 Ok(attr) => {
53 if let Some(repr) = &mut parser.repr {
54 **repr = Some(attr);
55 continue;
56 }
57 }
58 Err(err) => return cx.push(err),
59 }
David Tolnay7db73692019-10-20 14:51:12 -040060 }
David Tolnay3e628882020-05-10 15:30:14 -070061 return cx.error(attr, "unsupported attribute");
David Tolnay7db73692019-10-20 14:51:12 -040062 }
David Tolnay7db73692019-10-20 14:51:12 -040063}
64
65fn parse_doc_attribute(input: ParseStream) -> Result<LitStr> {
66 input.parse::<Token![=]>()?;
67 let lit: LitStr = input.parse()?;
68 Ok(lit)
69}
70
David Tolnaye86b9cf2020-05-10 14:24:29 -070071fn parse_derive_attribute(input: ParseStream) -> Result<Vec<Derive>> {
David Tolnay7db73692019-10-20 14:51:12 -040072 input
73 .parse_terminated::<Path, Token![,]>(Path::parse_mod_style)?
74 .into_iter()
David Tolnaye86b9cf2020-05-10 14:24:29 -070075 .map(|path| {
76 if let Some(ident) = path.get_ident() {
77 if let Some(derive) = Derive::from(ident) {
78 return Ok(derive);
79 }
80 }
81 Err(Error::new_spanned(path, "unsupported derive"))
David Tolnay7db73692019-10-20 14:51:12 -040082 })
83 .collect()
84}
David Tolnayddf69e22020-05-10 22:08:20 -070085
86fn parse_repr_attribute(input: ParseStream) -> Result<Atom> {
87 let begin = input.cursor();
88 let ident: Ident = input.parse()?;
89 if let Some(atom) = Atom::from(&ident) {
90 match atom {
91 U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize => return Ok(atom),
92 _ => {}
93 }
94 }
95 Err(Error::new_spanned(
96 begin.token_stream(),
97 "unrecognized repr",
98 ))
99}