summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--src/expand/env.cpp76
2 files changed, 77 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 52216f24..f351ba9d 100644
--- a/Makefile
+++ b/Makefile
@@ -69,6 +69,7 @@ OBJ += expand/concat.o expand/stringify.o expand/file_line.o
OBJ += expand/derive.o expand/lang_item.o
OBJ += expand/std_prelude.o expand/crate_tags.o
OBJ += expand/include.o
+OBJ += expand/env.o
OBJ += expand/rustc_diagnostics.o
OBJ += macro_rules/mod.o macro_rules/eval.o macro_rules/parse.o
OBJ += resolve/use.o resolve/index.o resolve/absolute.o
diff --git a/src/expand/env.cpp b/src/expand/env.cpp
new file mode 100644
index 00000000..989fbb7a
--- /dev/null
+++ b/src/expand/env.cpp
@@ -0,0 +1,76 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * expand/env.cpp
+ * - env! and option_env! macros
+ */
+#include <synext_macro.hpp>
+#include <parse/common.hpp>
+#include <ast/expr.hpp> // ExprNode_*
+#include <synext.hpp> // for Expand_BareExpr
+
+namespace {
+ // Read a string out of the input stream
+ ::std::string get_string(const Span& sp, const AST::Crate& crate, AST::Module& mod, const TokenTree& tt) {
+ auto lex = TTStream(tt);
+
+ auto n = Parse_ExprVal(lex);
+ ASSERT_BUG(sp, n, "No expression returned");
+ if( lex.lookahead(0) != TOK_EOF ) {
+ ERROR(sp, E0000, "Unexpected token after string literal - " << lex.getToken());
+ }
+ Expand_BareExpr(crate, mod, n);
+
+ auto* string_np = dynamic_cast<AST::ExprNode_String*>(&*n);
+ if( !string_np ) {
+ ERROR(sp, E0000, "Expected a string literal - got " << *n);
+ }
+ return mv$( string_np->m_value );
+ }
+}
+
+class CExpanderEnv:
+ public ExpandProcMacro
+{
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ {
+ if( ident != "" )
+ ERROR(sp, E0000, "env! doesn't take an ident");
+ ::std::string varname = get_string(sp, crate, mod, tt);
+
+ const char* var_val_cstr = getenv(varname.c_str());
+ if( !var_val_cstr ) {
+ ERROR(sp, E0000, "Environment variable '" << varname << "' not defined");
+ }
+ return box$( TTStreamO(TokenTree(Token(TOK_STRING, var_val_cstr))) );
+ }
+};
+
+class CExpanderOptionEnv:
+ public ExpandProcMacro
+{
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ {
+ if( ident != "" )
+ ERROR(sp, E0000, "option_env! doesn't take an ident");
+ ::std::string varname = get_string(sp, crate, mod, tt);
+
+ const char* var_val_cstr = getenv(varname.c_str());
+ if( !var_val_cstr ) {
+ return box$( TTStreamO(TokenTree(Token(TOK_IDENT, "None"))) );
+ }
+ else {
+ ::std::vector< TokenTree> rv;
+ rv.reserve(4);
+ rv.push_back( Token(TOK_IDENT, "Some") );
+ rv.push_back( Token(TOK_PAREN_OPEN) );
+ rv.push_back( Token(TOK_STRING, var_val_cstr) );
+ rv.push_back( Token(TOK_PAREN_CLOSE) );
+ return box$( TTStreamO(TokenTree( mv$(rv) )) );
+ }
+ }
+};
+
+STATIC_MACRO("env", CExpanderEnv);
+STATIC_MACRO("option_env", CExpanderOptionEnv);