diff options
Diffstat (limited to 'gcc/rust/expand/rust-macro-builtins-include.cc')
-rw-r--r-- | gcc/rust/expand/rust-macro-builtins-include.cc | 72 |
1 files changed, 58 insertions, 14 deletions
diff --git a/gcc/rust/expand/rust-macro-builtins-include.cc b/gcc/rust/expand/rust-macro-builtins-include.cc index c3b1e65..3d2a954 100644 --- a/gcc/rust/expand/rust-macro-builtins-include.cc +++ b/gcc/rust/expand/rust-macro-builtins-include.cc @@ -16,8 +16,11 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "rust-ast-fragment.h" +#include "rust-common.h" #include "rust-macro-builtins.h" #include "rust-macro-builtins-helpers.h" +#include "rust-session-manager.h" #include "optional.h" namespace Rust { /* Expand builtin macro include_bytes!("filename"), which includes the contents @@ -26,7 +29,8 @@ of the given file as reference to a byte array. Yields an expression of type tl::optional<AST::Fragment> MacroBuiltin::include_bytes_handler (location_t invoc_locus, - AST::MacroInvocData &invoc) + AST::MacroInvocData &invoc, + AST::InvocKind semicolon) { /* Get target filename from the macro invocation, which is treated as a path relative to the include!-ing file (currently being compiled). */ @@ -37,7 +41,12 @@ MacroBuiltin::include_bytes_handler (location_t invoc_locus, if (lit_expr == nullptr) return AST::Fragment::create_error (); - rust_assert (lit_expr->is_literal ()); + if (!lit_expr->is_literal ()) + { + auto token_tree = invoc.get_delim_tok_tree (); + return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))}, + token_tree.to_token_stream ()); + } std::string target_filename = source_relative_path (lit_expr->as_string (), invoc_locus); @@ -77,7 +86,9 @@ MacroBuiltin::include_bytes_handler (location_t invoc_locus, new AST::ArrayExpr (std::move (elems), {}, {}, invoc_locus)); auto borrow = std::unique_ptr<AST::Expr> ( - new AST::BorrowExpr (std::move (array), false, false, {}, invoc_locus)); + new AST::BorrowExpr (std::move (array), Mutability::Imm, + /* raw borrow */ false, + /* double borrow */ false, {}, invoc_locus)); auto node = AST::SingleASTNode (std::move (borrow)); @@ -90,7 +101,8 @@ MacroBuiltin::include_bytes_handler (location_t invoc_locus, tl::optional<AST::Fragment> MacroBuiltin::include_str_handler (location_t invoc_locus, - AST::MacroInvocData &invoc) + AST::MacroInvocData &invoc, + AST::InvocKind semicolon) { /* Get target filename from the macro invocation, which is treated as a path relative to the include!-ing file (currently being compiled). */ @@ -179,18 +191,39 @@ scope compile time. */ tl::optional<AST::Fragment> MacroBuiltin::include_handler (location_t invoc_locus, - AST::MacroInvocData &invoc) + AST::MacroInvocData &invoc, + AST::InvocKind semicolon) { + bool is_semicoloned = semicolon == AST::InvocKind::Semicoloned; /* Get target filename from the macro invocation, which is treated as a path relative to the include!-ing file (currently being compiled). */ - auto lit_expr + std::unique_ptr<AST::Expr> lit_expr = parse_single_string_literal (BuiltinMacro::Include, invoc.get_delim_tok_tree (), invoc_locus, - invoc.get_expander ()); + invoc.get_expander (), is_semicoloned); if (lit_expr == nullptr) return AST::Fragment::create_error (); - rust_assert (lit_expr->is_literal ()); + if (!lit_expr->is_literal ()) + { + // We have to expand an inner macro eagerly + auto token_tree = invoc.get_delim_tok_tree (); + + // parse_single_string_literal returned an AST::MacroInvocation, which + // can either be an AST::Item or AST::Expr. Depending on the context the + // original macro was invoked in, we will set AST::Item or AST::Expr + // appropriately. + if (is_semicoloned) + { + std::unique_ptr<AST::Item> lit_item = std::unique_ptr<AST::Item> ( + static_cast<AST::MacroInvocation *> (lit_expr.release ())); + return AST::Fragment ({AST::SingleASTNode (std::move (lit_item))}, + token_tree.to_token_stream ()); + } + else + return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))}, + token_tree.to_token_stream ()); + } std::string filename = source_relative_path (lit_expr->as_string (), invoc_locus); @@ -211,8 +244,14 @@ MacroBuiltin::include_handler (location_t invoc_locus, Lexer lex (target_filename, std::move (target_file), linemap); Parser<Lexer> parser (lex); + std::unique_ptr<AST::Expr> parsed_expr = nullptr; + std::vector<std::unique_ptr<AST::Item>> parsed_items{}; + + if (is_semicoloned) + parsed_items = parser.parse_items (); + else + parsed_expr = parser.parse_expr (); - auto parsed_items = parser.parse_items (); bool has_error = !parser.get_errors ().empty (); for (const auto &error : parser.get_errors ()) @@ -226,17 +265,22 @@ MacroBuiltin::include_handler (location_t invoc_locus, } std::vector<AST::SingleASTNode> nodes{}; - for (auto &item : parsed_items) + if (is_semicoloned) + for (auto &item : parsed_items) + { + AST::SingleASTNode node (std::move (item)); + nodes.push_back (node); + } + else { - AST::SingleASTNode node (std::move (item)); + AST::SingleASTNode node (std::move (parsed_expr)); nodes.push_back (node); } - // FIXME: This returns an empty vector of tokens and works fine, but is that // the expected behavior? `include` macros are a bit harder to reason about // since they include tokens. Furthermore, our lexer has no easy way to return // a slice of tokens like the MacroInvocLexer. So it gets even harder to - // extrac tokens from here. For now, let's keep it that way and see if it + // extract tokens from here. For now, let's keep it that way and see if it // eventually breaks, but I don't expect it to cause many issues since the // list of tokens is only used when a macro invocation mixes eager // macro invocations and already expanded tokens. Think @@ -246,4 +290,4 @@ MacroBuiltin::include_handler (location_t invoc_locus, // string literal. return AST::Fragment (nodes, std::vector<std::unique_ptr<AST::Token>> ()); } -} // namespace Rust
\ No newline at end of file +} // namespace Rust |