@@ -306,4 +306,71 @@ 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
+
333
+ parser.maybe_skip_token (COMMA);
334
+
335
+ std::unique_ptr<AST::LiteralExpr> error_expr = nullptr ;
336
+
337
+ if (parser.peek_current_token ()->get_id () != last_token_id)
338
+ {
339
+ if (parser.peek_current_token ()->get_id () != STRING_LITERAL)
340
+ {
341
+ rust_error_at (parser.peek_current_token ()->get_locus (),
342
+ " argument must be a string literal" );
343
+ return AST::ASTFragment::create_error ();
344
+ }
345
+
346
+ error_expr = parser.parse_literal_expr ();
347
+ parser.maybe_skip_token (COMMA);
348
+ }
349
+
350
+ if (parser.peek_current_token ()->get_id () != last_token_id)
351
+ {
352
+ rust_error_at (invoc_locus, " env! takes 1 or 2 arguments" );
353
+ return AST::ASTFragment::create_error ();
354
+ }
355
+
356
+ parser.skip_token (last_token_id);
357
+
358
+ auto env_value = getenv (lit_expr->as_string ().c_str ());
359
+
360
+ if (env_value == nullptr )
361
+ {
362
+ if (error_expr == nullptr )
363
+ {
364
+ rust_error_at (invoc_locus, " environment variable '%s' not defined" ,
365
+ lit_expr->as_string ().c_str ());
366
+ }
367
+ else
368
+ rust_error_at (invoc_locus, " %s" , error_expr->as_string ().c_str ());
369
+ return AST::ASTFragment::create_error ();
370
+ }
371
+
372
+ auto node = AST::SingleASTNode (make_string (invoc_locus, env_value));
373
+ return AST::ASTFragment ({node});
374
+ }
375
+
309
376
} // namespace Rust
0 commit comments