]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_macros/src/symbols.rs
Remove unused #[allow(...)] statements from compiler/
[rust.git] / compiler / rustc_macros / src / symbols.rs
1 use proc_macro::TokenStream;
2 use quote::quote;
3 use std::collections::HashSet;
4 use syn::parse::{Parse, ParseStream, Result};
5 use syn::{braced, parse_macro_input, Ident, LitStr, Token};
6
7 mod kw {
8     syn::custom_keyword!(Keywords);
9     syn::custom_keyword!(Symbols);
10 }
11
12 struct Keyword {
13     name: Ident,
14     value: LitStr,
15 }
16
17 impl Parse for Keyword {
18     fn parse(input: ParseStream<'_>) -> Result<Self> {
19         let name = input.parse()?;
20         input.parse::<Token![:]>()?;
21         let value = input.parse()?;
22         input.parse::<Token![,]>()?;
23
24         Ok(Keyword { name, value })
25     }
26 }
27
28 struct Symbol {
29     name: Ident,
30     value: Option<LitStr>,
31 }
32
33 impl Parse for Symbol {
34     fn parse(input: ParseStream<'_>) -> Result<Self> {
35         let name = input.parse()?;
36         let value = match input.parse::<Token![:]>() {
37             Ok(_) => Some(input.parse()?),
38             Err(_) => None,
39         };
40         input.parse::<Token![,]>()?;
41
42         Ok(Symbol { name, value })
43     }
44 }
45
46 /// A type used to greedily parse another type until the input is empty.
47 struct List<T>(Vec<T>);
48
49 impl<T: Parse> Parse for List<T> {
50     fn parse(input: ParseStream<'_>) -> Result<Self> {
51         let mut list = Vec::new();
52         while !input.is_empty() {
53             list.push(input.parse()?);
54         }
55         Ok(List(list))
56     }
57 }
58
59 struct Input {
60     keywords: List<Keyword>,
61     symbols: List<Symbol>,
62 }
63
64 impl Parse for Input {
65     fn parse(input: ParseStream<'_>) -> Result<Self> {
66         input.parse::<kw::Keywords>()?;
67         let content;
68         braced!(content in input);
69         let keywords = content.parse()?;
70
71         input.parse::<kw::Symbols>()?;
72         let content;
73         braced!(content in input);
74         let symbols = content.parse()?;
75
76         Ok(Input { keywords, symbols })
77     }
78 }
79
80 pub fn symbols(input: TokenStream) -> TokenStream {
81     let input = parse_macro_input!(input as Input);
82
83     let mut keyword_stream = quote! {};
84     let mut symbols_stream = quote! {};
85     let mut digits_stream = quote! {};
86     let mut prefill_stream = quote! {};
87     let mut counter = 0u32;
88     let mut keys = HashSet::<String>::new();
89     let mut prev_key: Option<String> = None;
90     let mut errors = Vec::<String>::new();
91
92     let mut check_dup = |str: &str, errors: &mut Vec<String>| {
93         if !keys.insert(str.to_string()) {
94             errors.push(format!("Symbol `{}` is duplicated", str));
95         }
96     };
97
98     let mut check_order = |str: &str, errors: &mut Vec<String>| {
99         if let Some(ref prev_str) = prev_key {
100             if str < prev_str {
101                 errors.push(format!("Symbol `{}` must precede `{}`", str, prev_str));
102             }
103         }
104         prev_key = Some(str.to_string());
105     };
106
107     // Generate the listed keywords.
108     for keyword in &input.keywords.0 {
109         let name = &keyword.name;
110         let value = &keyword.value;
111         check_dup(&value.value(), &mut errors);
112         prefill_stream.extend(quote! {
113             #value,
114         });
115         keyword_stream.extend(quote! {
116             #[allow(non_upper_case_globals)]
117             pub const #name: Symbol = Symbol::new(#counter);
118         });
119         counter += 1;
120     }
121
122     // Generate the listed symbols.
123     for symbol in &input.symbols.0 {
124         let name = &symbol.name;
125         let value = match &symbol.value {
126             Some(value) => value.value(),
127             None => name.to_string(),
128         };
129         check_dup(&value, &mut errors);
130         check_order(&name.to_string(), &mut errors);
131         prefill_stream.extend(quote! {
132             #value,
133         });
134         symbols_stream.extend(quote! {
135             #[allow(rustc::default_hash_types)]
136             #[allow(non_upper_case_globals)]
137             pub const #name: Symbol = Symbol::new(#counter);
138         });
139         counter += 1;
140     }
141
142     // Generate symbols for the strings "0", "1", ..., "9".
143     for n in 0..10 {
144         let n = n.to_string();
145         check_dup(&n, &mut errors);
146         prefill_stream.extend(quote! {
147             #n,
148         });
149         digits_stream.extend(quote! {
150             Symbol::new(#counter),
151         });
152         counter += 1;
153     }
154
155     if !errors.is_empty() {
156         for error in errors.into_iter() {
157             eprintln!("error: {}", error)
158         }
159         panic!("errors in `Keywords` and/or `Symbols`");
160     }
161
162     let tt = TokenStream::from(quote! {
163         macro_rules! keywords {
164             () => {
165                 #keyword_stream
166             }
167         }
168
169         macro_rules! define_symbols {
170             () => {
171                 #symbols_stream
172
173                 #[allow(non_upper_case_globals)]
174                 pub const digits_array: &[Symbol; 10] = &[
175                     #digits_stream
176                 ];
177             }
178         }
179
180         impl Interner {
181             pub fn fresh() -> Self {
182                 Interner::prefill(&[
183                     #prefill_stream
184                 ])
185             }
186         }
187     });
188
189     // To see the generated code generated, uncomment this line, recompile, and
190     // run the resulting output through `rustfmt`.
191     //eprintln!("{}", tt);
192
193     tt
194 }