@@ -26,7 +26,7 @@ use proc_macro2::{Span, TokenStream};
2626use quote:: quote;
2727use std:: collections:: HashMap ;
2828use 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 } ;
3030
3131#[ cfg( test) ]
3232mod tests;
@@ -59,6 +59,7 @@ struct Symbol {
5959enum Value {
6060 SameAsName ,
6161 String ( LitStr ) ,
62+ Env ( LitStr ) ,
6263}
6364
6465impl Parse for Symbol {
@@ -73,8 +74,27 @@ impl Parse for Symbol {
7374
7475impl Parse for Value {
7576 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+ ) )
7898 }
7999}
80100
@@ -198,12 +218,14 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
198218 // Generate the listed symbols.
199219 for symbol in input. symbols . iter ( ) {
200220 let name = & symbol. name ;
221+ check_order ( symbol. name . span ( ) , & name. to_string ( ) , & mut errors) ;
222+
201223 let value = match & symbol. value {
202224 Value :: SameAsName => name. to_string ( ) ,
203225 Value :: String ( lit) => lit. value ( ) ,
226+ Value :: Env ( _) => continue ,
204227 } ;
205228 let idx = entries. insert ( symbol. name . span ( ) , & value, & mut errors) ;
206- check_order ( symbol. name . span ( ) , & name. to_string ( ) , & mut errors) ;
207229
208230 prefill_stream. extend ( quote ! {
209231 #value,
@@ -222,6 +244,37 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
222244 } ) ;
223245 }
224246
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+
225278 let symbol_digits_base = entries. map [ "0" ] . idx ;
226279 let preinterned_symbols_count = entries. len ( ) ;
227280 let output = quote ! {
0 commit comments