@@ -26,7 +26,7 @@ use proc_macro2::{Span, TokenStream};
26
26
use quote:: quote;
27
27
use std:: collections:: HashMap ;
28
28
use syn:: parse:: { Parse , ParseStream , Result } ;
29
- use syn:: { braced, punctuated:: Punctuated , Ident , LitStr , Token } ;
29
+ use syn:: { braced, punctuated:: Punctuated , Expr , Ident , Lit , LitStr , Token } ;
30
30
31
31
#[ cfg( test) ]
32
32
mod tests;
@@ -59,6 +59,7 @@ struct Symbol {
59
59
enum Value {
60
60
SameAsName ,
61
61
String ( LitStr ) ,
62
+ Env ( LitStr ) ,
62
63
}
63
64
64
65
impl Parse for Symbol {
@@ -73,8 +74,27 @@ impl Parse for Symbol {
73
74
74
75
impl Parse for Value {
75
76
fn parse ( input : ParseStream < ' _ > ) -> Result < Self > {
76
- let lit: LitStr = input. parse ( ) ?;
77
- Ok ( Value :: String ( lit) )
77
+ let expr: Expr = input. parse ( ) ?;
78
+ match & expr {
79
+ Expr :: Lit ( expr) => {
80
+ if let Lit :: Str ( lit) = & expr. lit {
81
+ return Ok ( Value :: String ( lit. clone ( ) ) ) ;
82
+ }
83
+ }
84
+ Expr :: Macro ( expr) => {
85
+ if expr. mac . path . is_ident ( "env" ) && let Ok ( lit) = expr. mac . parse_body ( ) {
86
+ return Ok ( Value :: Env ( lit) ) ;
87
+ }
88
+ }
89
+ _ => { }
90
+ }
91
+ Err ( syn:: Error :: new_spanned (
92
+ expr,
93
+ concat ! (
94
+ "unsupported expression for symbol value; implement support for this in " ,
95
+ file!( ) ,
96
+ ) ,
97
+ ) )
78
98
}
79
99
}
80
100
@@ -198,12 +218,14 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
198
218
// Generate the listed symbols.
199
219
for symbol in input. symbols . iter ( ) {
200
220
let name = & symbol. name ;
221
+ check_order ( symbol. name . span ( ) , & name. to_string ( ) , & mut errors) ;
222
+
201
223
let value = match & symbol. value {
202
224
Value :: SameAsName => name. to_string ( ) ,
203
225
Value :: String ( lit) => lit. value ( ) ,
226
+ Value :: Env ( _) => continue ,
204
227
} ;
205
228
let idx = entries. insert ( symbol. name . span ( ) , & value, & mut errors) ;
206
- check_order ( symbol. name . span ( ) , & name. to_string ( ) , & mut errors) ;
207
229
208
230
prefill_stream. extend ( quote ! {
209
231
#value,
@@ -222,6 +244,37 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
222
244
} ) ;
223
245
}
224
246
247
+ // Symbols whose value comes from an environment variable. It's allowed for
248
+ // these to have the same value as another symbol.
249
+ for symbol in & input. symbols {
250
+ let env_var = match & symbol. value {
251
+ Value :: Env ( lit) => lit,
252
+ _ => continue ,
253
+ } ;
254
+
255
+ let value = match proc_macro:: tracked_env:: var ( env_var. value ( ) ) {
256
+ Ok ( value) => value,
257
+ Err ( err) => {
258
+ errors. error ( symbol. name . span ( ) , err. to_string ( ) ) ;
259
+ continue ;
260
+ }
261
+ } ;
262
+
263
+ let idx = if let Some ( prev) = entries. map . get ( & value) {
264
+ prev. idx
265
+ } else {
266
+ prefill_stream. extend ( quote ! {
267
+ #value,
268
+ } ) ;
269
+ entries. insert ( symbol. name . span ( ) , & value, & mut errors)
270
+ } ;
271
+
272
+ let name = & symbol. name ;
273
+ symbols_stream. extend ( quote ! {
274
+ pub const #name: Symbol = Symbol :: new( #idx) ;
275
+ } ) ;
276
+ }
277
+
225
278
let symbol_digits_base = entries. map [ "0" ] . idx ;
226
279
let preinterned_symbols_count = entries. len ( ) ;
227
280
let output = quote ! {
0 commit comments