blob: 1cb06571613384f73a30f4476f3683a3d155067e [file] [log] [blame]
David Tolnay3e628882020-05-10 15:30:14 -07001use crate::syntax::report::Errors;
David Tolnay7db73692019-10-20 14:51:12 -04002use crate::syntax::{Derive, Doc};
3use proc_macro2::Ident;
David Tolnayb129ea72020-05-10 14:29:30 -07004use syn::parse::{ParseStream, Parser as _};
David Tolnay7db73692019-10-20 14:51:12 -04005use syn::{Attribute, Error, LitStr, Path, Result, Token};
6
David Tolnayb129ea72020-05-10 14:29:30 -07007#[derive(Default)]
8pub struct Parser<'a> {
9 pub doc: Option<&'a mut Doc>,
10 pub derives: Option<&'a mut Vec<Derive>>,
11}
12
David Tolnay3e628882020-05-10 15:30:14 -070013pub(super) fn parse_doc(cx: &mut Errors, attrs: &[Attribute]) -> Doc {
David Tolnay7db73692019-10-20 14:51:12 -040014 let mut doc = Doc::new();
David Tolnayb129ea72020-05-10 14:29:30 -070015 parse(
David Tolnay3e628882020-05-10 15:30:14 -070016 cx,
David Tolnayb129ea72020-05-10 14:29:30 -070017 attrs,
18 Parser {
19 doc: Some(&mut doc),
20 ..Parser::default()
21 },
David Tolnay3e628882020-05-10 15:30:14 -070022 );
23 doc
David Tolnay7db73692019-10-20 14:51:12 -040024}
25
David Tolnay3e628882020-05-10 15:30:14 -070026pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) {
David Tolnay7db73692019-10-20 14:51:12 -040027 for attr in attrs {
28 if attr.path.is_ident("doc") {
David Tolnay3e628882020-05-10 15:30:14 -070029 match parse_doc_attribute.parse2(attr.tokens.clone()) {
30 Ok(lit) => {
31 if let Some(doc) = &mut parser.doc {
32 doc.push(lit);
33 continue;
34 }
35 }
36 Err(err) => return cx.push(err),
David Tolnayb129ea72020-05-10 14:29:30 -070037 }
David Tolnay7db73692019-10-20 14:51:12 -040038 } else if attr.path.is_ident("derive") {
David Tolnay3e628882020-05-10 15:30:14 -070039 match attr.parse_args_with(parse_derive_attribute) {
40 Ok(attr) => {
41 if let Some(derives) = &mut parser.derives {
42 derives.extend(attr);
43 continue;
44 }
45 }
46 Err(err) => return cx.push(err),
David Tolnay7db73692019-10-20 14:51:12 -040047 }
48 }
David Tolnay3e628882020-05-10 15:30:14 -070049 return cx.error(attr, "unsupported attribute");
David Tolnay7db73692019-10-20 14:51:12 -040050 }
David Tolnay7db73692019-10-20 14:51:12 -040051}
52
53fn parse_doc_attribute(input: ParseStream) -> Result<LitStr> {
54 input.parse::<Token![=]>()?;
55 let lit: LitStr = input.parse()?;
56 Ok(lit)
57}
58
David Tolnaye86b9cf2020-05-10 14:24:29 -070059fn parse_derive_attribute(input: ParseStream) -> Result<Vec<Derive>> {
David Tolnay7db73692019-10-20 14:51:12 -040060 input
61 .parse_terminated::<Path, Token![,]>(Path::parse_mod_style)?
62 .into_iter()
David Tolnaye86b9cf2020-05-10 14:24:29 -070063 .map(|path| {
64 if let Some(ident) = path.get_ident() {
65 if let Some(derive) = Derive::from(ident) {
66 return Ok(derive);
67 }
68 }
69 Err(Error::new_spanned(path, "unsupported derive"))
David Tolnay7db73692019-10-20 14:51:12 -040070 })
71 .collect()
72}
73
74impl Derive {
75 pub fn from(ident: &Ident) -> Option<Self> {
76 match ident.to_string().as_str() {
77 "Clone" => Some(Derive::Clone),
78 "Copy" => Some(Derive::Copy),
79 _ => None,
80 }
81 }
82}
83
84impl AsRef<str> for Derive {
85 fn as_ref(&self) -> &str {
86 match self {
87 Derive::Clone => "Clone",
88 Derive::Copy => "Copy",
89 }
90 }
91}