2525//! ```
2626
2727use std:: collections:: HashMap ;
28+ use std:: collections:: hash_map:: Entry ;
2829
2930use proc_macro2:: { Span , TokenStream } ;
3031use quote:: quote;
3132use syn:: parse:: { Parse , ParseStream , Result } ;
3233use syn:: punctuated:: Punctuated ;
33- use syn:: { Expr , Ident , Lit , LitStr , Macro , Token , braced} ;
34+ use syn:: { Expr , Ident , Lit , LitStr , Macro , Token , braced, bracketed } ;
3435
3536#[ cfg( test) ]
3637mod tests;
@@ -147,25 +148,44 @@ struct Predefined {
147148 span_of_name : Span ,
148149}
149150
151+ struct Duplicate {
152+ name : String ,
153+ span_of_name : Span ,
154+ }
155+
150156struct Entries {
151157 map : HashMap < String , Predefined > ,
158+ prefill_stream : TokenStream ,
152159}
153160
154161impl Entries {
155162 fn with_capacity ( capacity : usize ) -> Self {
156- Entries { map : HashMap :: with_capacity ( capacity) }
163+ Entries { map : HashMap :: with_capacity ( capacity) , prefill_stream : TokenStream :: new ( ) }
164+ }
165+
166+ fn try_insert ( & mut self , span : Span , s : String ) -> ( u32 , Option < Duplicate > ) {
167+ let len = self . len ( ) ;
168+ match self . map . entry ( s) {
169+ Entry :: Occupied ( entry) => {
170+ let Predefined { idx, span_of_name } = * entry. get ( ) ;
171+ ( idx, Some ( Duplicate { name : entry. key ( ) . clone ( ) , span_of_name } ) )
172+ }
173+ Entry :: Vacant ( entry) => {
174+ let s = entry. key ( ) . as_str ( ) ;
175+ self . prefill_stream . extend ( quote ! { #s, } ) ;
176+ entry. insert ( Predefined { idx : len, span_of_name : span } ) ;
177+ ( len, None )
178+ }
179+ }
157180 }
158181
159- fn insert ( & mut self , span : Span , s : & str , errors : & mut Errors ) -> u32 {
160- if let Some ( prev) = self . map . get ( s) {
161- errors. error ( span, format ! ( "Symbol `{s}` is duplicated" ) ) ;
162- errors. error ( prev. span_of_name , "location of previous definition" . to_string ( ) ) ;
163- prev. idx
164- } else {
165- let idx = self . len ( ) ;
166- self . map . insert ( s. to_string ( ) , Predefined { idx, span_of_name : span } ) ;
167- idx
182+ fn insert ( & mut self , span : Span , s : String , errors : & mut Errors ) -> u32 {
183+ let ( idx, duplicate) = self . try_insert ( span, s) ;
184+ if let Some ( Duplicate { name, span_of_name } ) = duplicate {
185+ errors. error ( span, format ! ( "Symbol `{name}` is duplicated" ) ) ;
186+ errors. error ( span_of_name, "location of previous definition" . to_string ( ) ) ;
168187 }
188+ idx
169189 }
170190
171191 fn len ( & self ) -> u32 {
@@ -188,18 +208,13 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
188208
189209 let mut keyword_stream = quote ! { } ;
190210 let mut symbols_stream = quote ! { } ;
191- let mut prefill_stream = quote ! { } ;
192211 let mut entries = Entries :: with_capacity ( input. keywords . len ( ) + input. symbols . len ( ) + 10 ) ;
193212
194213 // Generate the listed keywords.
195214 for keyword in input. keywords . iter ( ) {
196215 let name = & keyword. name ;
197- let value = & keyword. value ;
198- let value_string = value. value ( ) ;
199- let idx = entries. insert ( keyword. name . span ( ) , & value_string, & mut errors) ;
200- prefill_stream. extend ( quote ! {
201- #value,
202- } ) ;
216+ let value_string = keyword. value . value ( ) ;
217+ let idx = entries. insert ( keyword. name . span ( ) , value_string, & mut errors) ;
203218 keyword_stream. extend ( quote ! {
204219 pub const #name: Symbol = Symbol :: new( #idx) ;
205220 } ) ;
@@ -224,23 +239,15 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
224239 continue ;
225240 }
226241 } ;
227- let idx = entries. insert ( symbol. name . span ( ) , & value, & mut errors) ;
228-
229- prefill_stream. extend ( quote ! {
230- #value,
231- } ) ;
242+ let idx = entries. insert ( symbol. name . span ( ) , value, & mut errors) ;
232243 symbols_stream. extend ( quote ! {
233244 pub const #name: Symbol = Symbol :: new( #idx) ;
234245 } ) ;
235246 }
236247
237248 // Generate symbols for the strings "0", "1", ..., "9".
238249 for n in 0 ..10 {
239- let n = n. to_string ( ) ;
240- entries. insert ( Span :: call_site ( ) , & n, & mut errors) ;
241- prefill_stream. extend ( quote ! {
242- #n,
243- } ) ;
250+ entries. insert ( Span :: call_site ( ) , n. to_string ( ) , & mut errors) ;
244251 }
245252
246253 // Symbols whose value comes from an environment variable. It's allowed for
@@ -267,23 +274,16 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
267274 }
268275 } ;
269276
270- let idx = if let Some ( prev) = entries. map . get ( & value) {
271- prev. idx
272- } else {
273- prefill_stream. extend ( quote ! {
274- #value,
275- } ) ;
276- entries. insert ( symbol. name . span ( ) , & value, & mut errors)
277- } ;
278-
279277 let name = & symbol. name ;
278+ let ( idx, _) = entries. try_insert ( name. span ( ) , value) ;
280279 symbols_stream. extend ( quote ! {
281280 pub const #name: Symbol = Symbol :: new( #idx) ;
282281 } ) ;
283282 }
284283
285284 let symbol_digits_base = entries. map [ "0" ] . idx ;
286285 let predefined_symbols_count = entries. len ( ) ;
286+ let prefill_stream = entries. prefill_stream ;
287287 let output = quote ! {
288288 const SYMBOL_DIGITS_BASE : u32 = #symbol_digits_base;
289289
@@ -309,14 +309,124 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
309309 impl Interner {
310310 /// Creates an `Interner` with the predefined symbols from the `symbols!` macro and
311311 /// any extra symbols provided by external drivers such as Clippy
312- pub ( crate ) fn with_extra_symbols ( extra_symbols : & [ & ' static str ] ) -> Self {
312+ pub ( crate ) fn new ( driver_symbols : Option < & [ & ' static str ] > ) -> Self {
313313 Interner :: prefill(
314- & [ #prefill_stream] ,
315- extra_symbols,
314+ driver_symbols. unwrap_or( & [ #prefill_stream] )
316315 )
317316 }
318317 }
318+
319+ /// Allows drivers to define extra preinterned symbols, the expanded `PREINTERNED_SYMBOLS`
320+ /// is to be provided to `rustc_interface::Config`
321+ #[ macro_export]
322+ macro_rules! extra_symbols {
323+ ( $( #[ macro_export] $further_symbols: ident; ) ? Symbols { $( $tt: tt) * } ) => {
324+ rustc_macros:: extra_symbols_impl! {
325+ $( $further_symbols) ? [ #prefill_stream] $( $tt) *
326+ }
327+ } ;
328+ }
319329 } ;
320330
321331 ( output, errors. list )
322332}
333+
334+ #[ derive( Default ) ]
335+ struct ExtraSymbols {
336+ macro_ident : Option < Ident > ,
337+ predefined : Punctuated < LitStr , Token ! [ , ] > ,
338+ extra_symbols : Punctuated < Symbol , Token ! [ , ] > ,
339+ }
340+
341+ impl Parse for ExtraSymbols {
342+ fn parse ( input : ParseStream < ' _ > ) -> Result < Self > {
343+ let macro_ident: Option < Ident > = input. parse ( ) ?;
344+
345+ let content;
346+ bracketed ! ( content in input) ;
347+ let predefined = Punctuated :: parse_terminated ( & content) ?;
348+
349+ let extra_symbols = Punctuated :: parse_terminated ( & input) ?;
350+
351+ Ok ( ExtraSymbols { macro_ident, predefined, extra_symbols } )
352+ }
353+ }
354+
355+ pub ( super ) fn extra_symbols ( input : TokenStream ) -> TokenStream {
356+ let mut errors = Errors :: default ( ) ;
357+
358+ let input: ExtraSymbols = match syn:: parse2 ( input) {
359+ Ok ( input) => input,
360+ Err ( e) => {
361+ errors. list . push ( e) ;
362+ Default :: default ( )
363+ }
364+ } ;
365+
366+ let mut symbol_stream = TokenStream :: new ( ) ;
367+ let mut duplicate_symbols = TokenStream :: new ( ) ;
368+
369+ let mut entries = Entries :: with_capacity ( input. predefined . len ( ) + input. extra_symbols . len ( ) ) ;
370+ for lit in & input. predefined {
371+ entries. insert ( lit. span ( ) , lit. value ( ) , & mut errors) ;
372+ }
373+
374+ for symbol in input. extra_symbols {
375+ let value = match symbol. value {
376+ Value :: SameAsName => symbol. name . to_string ( ) ,
377+ Value :: String ( lit) => lit. value ( ) ,
378+ _ => {
379+ errors. error (
380+ symbol. name . span ( ) ,
381+ "unsupported expression for extra symbol value" . to_string ( ) ,
382+ ) ;
383+ continue ;
384+ }
385+ } ;
386+
387+ let name = & symbol. name ;
388+ let ( idx, duplicate) = entries. try_insert ( name. span ( ) , value) ;
389+ if duplicate. is_some ( ) {
390+ duplicate_symbols. extend ( quote ! { #name, } ) ;
391+ }
392+ symbol_stream. extend ( quote ! {
393+ pub const #name: Symbol = Symbol :: new( #idx) ;
394+ } ) ;
395+ }
396+
397+ let prefill_stream = entries. prefill_stream ;
398+
399+ let further_symbols = if let Some ( macro_ident) = input. macro_ident {
400+ quote ! {
401+ #[ macro_export]
402+ macro_rules! #macro_ident {
403+ ( $( #[ macro_export] $further_symbols: ident; ) ? Symbols { $( $tt: tt) * } ) => {
404+ rustc_macros:: extra_symbols_impl! {
405+ $( $further_symbols) ? [ #prefill_stream] $( $tt) *
406+ }
407+ } ;
408+ }
409+ }
410+ } else {
411+ TokenStream :: new ( )
412+ } ;
413+
414+ let mut output = quote ! {
415+ /// To be supplied to `rustc_interface::Config`
416+ pub const PREINTERNED_SYMBOLS : & [ & str ] = & [
417+ #prefill_stream
418+ ] ;
419+
420+ pub const DUPLICATE_SYMBOLS : & [ Symbol ] = & [
421+ #duplicate_symbols
422+ ] ;
423+
424+ #symbol_stream
425+
426+ #further_symbols
427+ } ;
428+
429+ output. extend ( errors. list . into_iter ( ) . map ( |e| e. into_compile_error ( ) ) ) ;
430+
431+ output
432+ }
0 commit comments