/* * MRustC - Rust Compiler * - By John Hodge (Mutabah/thePowersGang) * * expand/include.cpp * - include!/include_str!/include_bytes! support */ #include #include // for Expand_BareExpr #include #include // for GET_CHECK_TOK #include #include // Lexer (new files) #include namespace { ::std::string get_string(const Span& sp, TokenStream& lex, const ::AST::Crate& crate, AST::Module& mod) { auto n = Parse_ExprVal(lex); ASSERT_BUG(sp, n, "No expression returned"); Expand_BareExpr(crate, mod, n); auto* string_np = dynamic_cast(&*n); if( !string_np ) { ERROR(sp, E0000, "include! requires a string literal - got " << *n); } return mv$( string_np->m_value ); } ::std::string get_path_relative_to(const ::std::string& base_path, ::std::string path) { if( path[0] == '/' ) { return path; } else if( base_path.size() == 0 ) { return path; } else if( base_path[base_path.size()-1] == '/' ) { return base_path + path; } else { auto slash = base_path.find_last_of('/'); if( slash == ::std::string::npos ) { return path; } else { slash += 1; ::std::string rv; rv.reserve( slash + path.size() ); rv.append( base_path.begin(), base_path.begin() + slash ); rv.append( path.begin(), path.end() ); return rv; } } } }; class CIncludeExpander: public ExpandProcMacro { ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override { if( ident != "" ) ERROR(sp, E0000, "include! doesn't take an ident"); Token tok; auto lex = TTStream(tt); auto path = get_string(sp, lex, crate, mod); GET_CHECK_TOK(tok, lex, TOK_EOF); ::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path)); return box$( Lexer(file_path) ); } }; // TODO: include_str! and include_bytes! STATIC_MACRO("include", CIncludeExpander);