blob: 7dab26300b5831a39f8652270646ec3521a35cf2 [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 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 Tolnayf4b93342020-11-27 13:59:42 -080032 match attr.parse_args_with(|attr: ParseStream| parse_derive_attribute(cx, attr)) {
David Tolnay3e628882020-05-10 15:30:14 -070033 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 Tolnaya2dfcbf2020-12-21 15:46:24 -080051 } else if attr.path.is_ident("namespace") {
52 match parse_namespace_attribute.parse2(attr.tokens.clone()) {
53 Ok(attr) => {
54 if let Some(namespace) = &mut parser.namespace {
55 **namespace = attr;
56 continue;
57 }
58 }
59 Err(err) => return cx.push(err),
60 }
David Tolnay1039a242020-10-09 19:18:12 -070061 } else if attr.path.is_ident("cxx_name") {
62 match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
63 Ok(attr) => {
64 if let Some(cxx_name) = &mut parser.cxx_name {
65 **cxx_name = Some(attr);
66 continue;
67 }
68 }
69 Err(err) => return cx.push(err),
70 }
71 } else if attr.path.is_ident("rust_name") {
72 match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
73 Ok(attr) => {
74 if let Some(rust_name) = &mut parser.rust_name {
75 **rust_name = Some(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 Tolnayf4b93342020-11-27 13:59:42 -080092fn parse_derive_attribute(cx: &mut Errors, input: ParseStream) -> Result<Vec<Derive>> {
93 let paths = input.parse_terminated::<Path, Token![,]>(Path::parse_mod_style)?;
94
95 let mut derives = Vec::new();
96 for path in paths {
97 if let Some(ident) = path.get_ident() {
98 if let Some(derive) = Derive::from(ident) {
99 derives.push(derive);
100 continue;
David Tolnaye86b9cf2020-05-10 14:24:29 -0700101 }
David Tolnayf4b93342020-11-27 13:59:42 -0800102 }
103 cx.error(path, "unsupported derive");
104 }
105 Ok(derives)
David Tolnay7db73692019-10-20 14:51:12 -0400106}
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
David Tolnaya2dfcbf2020-12-21 15:46:24 -0800125fn parse_namespace_attribute(input: ParseStream) -> Result<Namespace> {
126 input.parse::<Token![=]>()?;
127 let namespace = input.parse::<Namespace>()?;
128 Ok(namespace)
129}
130
David Tolnay1039a242020-10-09 19:18:12 -0700131fn parse_function_alias_attribute(input: ParseStream) -> Result<Ident> {
132 input.parse::<Token![=]>()?;
133 if input.peek(LitStr) {
134 let lit: LitStr = input.parse()?;
135 lit.parse()
136 } else {
137 input.parse()
138 }
139}