@@ -306,4 +306,74 @@ MacroBuiltin::concat (Location invoc_locus, AST::MacroInvocData &invoc)
306
306
return AST::ASTFragment ({node});
307
307
}
308
308
309
+ /* Expand builtin macro env!(), which inspects an environment variable at
310
+ compile time. */
311
+
312
+ AST::ASTFragment
313
+ MacroBuiltin::env (Location invoc_locus, AST::MacroInvocData &invoc)
314
+ {
315
+ auto invoc_token_tree = invoc.get_delim_tok_tree ();
316
+ MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
317
+ Parser<MacroInvocLexer> parser (std::move (lex));
318
+
319
+ auto last_token_id = macro_end_token (invoc_token_tree, parser);
320
+
321
+ if (parser.peek_current_token ()->get_id () != STRING_LITERAL)
322
+ {
323
+ if (parser.peek_current_token ()->get_id () == last_token_id)
324
+ rust_error_at (invoc_locus, " env! takes 1 or 2 arguments" );
325
+ else
326
+ rust_error_at (parser.peek_current_token ()->get_locus (),
327
+ " argument must be a string literal" );
328
+ return AST::ASTFragment::create_error ();
329
+ }
330
+
331
+ auto lit_expr = parser.parse_literal_expr ();
332
+ auto comma_skipped = parser.maybe_skip_token (COMMA);
333
+
334
+ std::unique_ptr<AST::LiteralExpr> error_expr = nullptr ;
335
+
336
+ if (parser.peek_current_token ()->get_id () != last_token_id)
337
+ {
338
+ if (!comma_skipped)
339
+ {
340
+ rust_error_at (parser.peek_current_token ()->get_locus (),
341
+ " expected token: %<,%>" );
342
+ return AST::ASTFragment::create_error ();
343
+ }
344
+ if (parser.peek_current_token ()->get_id () != STRING_LITERAL)
345
+ {
346
+ rust_error_at (parser.peek_current_token ()->get_locus (),
347
+ " argument must be a string literal" );
348
+ return AST::ASTFragment::create_error ();
349
+ }
350
+
351
+ error_expr = parser.parse_literal_expr ();
352
+ parser.maybe_skip_token (COMMA);
353
+ }
354
+
355
+ if (parser.peek_current_token ()->get_id () != last_token_id)
356
+ {
357
+ rust_error_at (invoc_locus, " env! takes 1 or 2 arguments" );
358
+ return AST::ASTFragment::create_error ();
359
+ }
360
+
361
+ parser.skip_token (last_token_id);
362
+
363
+ auto env_value = getenv (lit_expr->as_string ().c_str ());
364
+
365
+ if (env_value == nullptr )
366
+ {
367
+ if (error_expr == nullptr )
368
+ rust_error_at (invoc_locus, " environment variable %qs not defined" ,
369
+ lit_expr->as_string ().c_str ());
370
+ else
371
+ rust_error_at (invoc_locus, " %s" , error_expr->as_string ().c_str ());
372
+ return AST::ASTFragment::create_error ();
373
+ }
374
+
375
+ auto node = AST::SingleASTNode (make_string (invoc_locus, env_value));
376
+ return AST::ASTFragment ({node});
377
+ }
378
+
309
379
} // namespace Rust
0 commit comments