diff --git a/src/ast/attrs.hpp b/src/ast/attrs.hpp index 9daa4667..81bd5883 100644 --- a/src/ast/attrs.hpp +++ b/src/ast/attrs.hpp @@ -113,6 +113,8 @@ class Attribute const Span& span() const { return m_span; } const AttributeName& name() const { return m_name; } const TokenTree& data() const { return m_data; } + + TokenTree& data_mut() { return m_data; } /// Parses the data as a `="string"` and returns the string diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index fbac90c6..9b7390d7 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -2478,12 +2478,14 @@ ::HIR::CratePtr LowerHIR_FromAST(::AST::Crate crate) struct H { static void fix_macro_contents(std::vector& rule_contents) { - for(auto& ent : rule_contents) + for( auto it = rule_contents.begin(); it != rule_contents.end(); ) { - if(auto* tok = ent.opt_Token()) + if(auto* tok = it->opt_Token()) { - struct H { - static void emit_ast(std::vector& out, const AST::ExprNode& e) + //TODO: Can this share with `proc_macro`? Maybe a function on AST types to generate a token tree from the AST again. + struct NewToks { + std::vector out; + void emit_ast(const AST::ExprNode& e) { if( const auto* ep = dynamic_cast(&e) ) { out.push_back( Token(ep->m_value, ep->m_datatype) ); @@ -2492,9 +2494,57 @@ ::HIR::CratePtr LowerHIR_FromAST(::AST::Crate crate) throw std::runtime_error("Unknown node type"); } } + void emit_tokentree(TokenTree& tt) { + if( tt.is_token() ) { + emit_token(tt.tok()); + } + else { + for(size_t i = 0; i < tt.size(); i ++) { + emit_tokentree(tt[i]); + } + } + } + + void emit_token(Token& tok) + { + switch(tok.type()) + { + case TOK_INTERPOLATED_PATH: + case TOK_INTERPOLATED_TYPE: + case TOK_INTERPOLATED_PATTERN: + case TOK_INTERPOLATED_STMT: + case TOK_INTERPOLATED_BLOCK: + case TOK_INTERPOLATED_ITEM: + case TOK_INTERPOLATED_VIS: + // Emit as a token tree with no separator + TODO(Span(), "Convert interpolated macro fragment: " << tok); + break; + case TOK_INTERPOLATED_META: { + auto& i = tok.frag_meta(); + for(const auto& e : i.name().elems) + { + if( &e != &i.name().elems.front() ) + out.push_back(Token(TOK_DOUBLE_COLON)); + out.push_back(Token(TOK_IDENT, e)); + } + emit_tokentree(i.data_mut()); + break; } + case TOK_INTERPOLATED_EXPR: + try { + emit_ast(*tok.take_frag_node()); + } + catch(const std::exception& e) { + TODO(Span(), "Convert interpolated macro fragment: " << tok << " - " << e.what()); + } + break; + default: + out.push_back(std::move(tok)); + return; + } + } }; - std::vector new_toks; + NewToks new_toks; switch(tok->type()) { case TOK_INTERPOLATED_PATH: @@ -2502,30 +2552,31 @@ ::HIR::CratePtr LowerHIR_FromAST(::AST::Crate crate) case TOK_INTERPOLATED_PATTERN: case TOK_INTERPOLATED_STMT: case TOK_INTERPOLATED_BLOCK: - case TOK_INTERPOLATED_META: case TOK_INTERPOLATED_ITEM: case TOK_INTERPOLATED_VIS: - // Emit as a token tree with no separator - TODO(Span(), "Convert interpolated macro fragment: " << *tok); - break; + case TOK_INTERPOLATED_META: case TOK_INTERPOLATED_EXPR: - try { - H::emit_ast(new_toks, *tok->take_frag_node()); - } - catch(const std::exception& e) { - TODO(Span(), "Convert interpolated macro fragment: " << *tok << " - " << e.what()); - } + new_toks.emit_token(*tok); break; default: + ++ it; continue; } - if( new_toks.size() == 1 ) { - *tok = std::move(new_toks.front()); + if( new_toks.out.size() == 0 ) { + it = rule_contents.erase(it); } else { - TODO(Span(), "Expand interpolated macro fragment to multiple (or no) tokens"); + *it = std::move(new_toks.out.front()); + it = rule_contents.insert(it+1, + std::move_iterator< decltype(new_toks.out.begin()) >(new_toks.out.begin()+1), + std::move_iterator< decltype(new_toks.out.begin()) >(new_toks.out.end()) + ); + it += new_toks.out.size(); } } + else { + ++it; + } } } static void fix_macros_in_mod(HIR::Module& mod)