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