diff options
Diffstat (limited to 'src/expand/mod.cpp')
-rw-r--r-- | src/expand/mod.cpp | 120 |
1 files changed, 93 insertions, 27 deletions
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 88d16216..b5bbc1a4 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -312,11 +312,9 @@ struct CExpandExpr: assert( ! this->replacement ); } void visit_vector(::std::vector< ::std::unique_ptr<AST::ExprNode> >& cnodes) { - for( auto& child : cnodes ) { - this->visit(child); - } - // Delete null children for( auto it = cnodes.begin(); it != cnodes.end(); ) { + assert( it->get() ); + this->visit(*it); if( it->get() == nullptr ) { it = cnodes.erase( it ); } @@ -326,48 +324,83 @@ struct CExpandExpr: } } - void visit(::AST::ExprNode_Macro& node) override + ::AST::ExprNodeP visit_macro(::AST::ExprNode_Macro& node, ::std::vector< ::AST::ExprNodeP>* nodes_out) { - TRACE_FUNCTION_F("ExprNode_Macro - name = " << node.m_name); + TRACE_FUNCTION_F(node.m_name << "!"); if( node.m_name == "" ) { - return ; + return ::AST::ExprNodeP(); } + ::AST::ExprNodeP rv; auto& mod = this->cur_mod(); - auto ttl = Expand_Macro( - crate, modstack, mod, - Span(node.get_pos()), - node.m_name, node.m_ident, node.m_tokens - ); - if( ttl.get() != nullptr ) + auto ttl = Expand_Macro( crate, modstack, mod, Span(node.get_pos()), node.m_name, node.m_ident, node.m_tokens ); + if( !ttl.get() ) + { + // No expansion + } + else { - if( ttl->lookahead(0) != TOK_EOF ) + while( ttl->lookahead(0) != TOK_EOF ) { SET_MODULE( (*ttl), mod ); + // Reparse as expression / item bool add_silence_if_end = false; ::std::shared_ptr< AST::Module> tmp_local_mod; auto& local_mod_ptr = (this->current_block ? this->current_block->m_local_mod : tmp_local_mod); - DEBUG("-- Parsing as expression line (legacy)"); + DEBUG("-- Parsing as expression line"); auto newexpr = Parse_ExprBlockLine_WithItems(*ttl, local_mod_ptr, add_silence_if_end); + + if( tmp_local_mod ) + TODO(node.get_pos(), "Handle edge case where a macro expansion outside of a _Block creates an item"); + if( newexpr ) { - // TODO: use add_silence_if_end - Applies if this node is the last node in the block. - - // Then call visit on it again - DEBUG("--- Visiting new node"); - this->visit(newexpr); - // And schedule it to replace the previous - replacement = mv$(newexpr); + if( nodes_out ) { + nodes_out->push_back( mv$(newexpr) ); + } + else { + assert( !rv ); + rv = mv$(newexpr); + } } else { - // TODO: Delete this node somehow? Or just leave it for later. + // Expansion line just added a new item + } + + if( ttl->lookahead(0) != TOK_EOF ) + { + if( !nodes_out ) { + ERROR(node.get_pos(), E0000, "Unused tokens at the end of macro expansion - " << ttl->getToken()); + } } - ASSERT_BUG(node.get_pos(), !tmp_local_mod, "TODO: Handle edge case where a macro expansion outside of a _Block creates an item"); } - DEBUG("ExprNode_Macro - replacement = " << replacement.get()); - node.m_name = ""; + } + + node.m_name = ""; + return mv$(rv); + } + + void visit(::AST::ExprNode_Macro& node) override + { + TRACE_FUNCTION_F("ExprNode_Macro - name = " << node.m_name); + if( node.m_name == "" ) { + return ; + } + + replacement = this->visit_macro(node, nullptr); + + if( this->replacement ) + { + DEBUG("--- Visiting new node"); + auto n = mv$(this->replacement); + this->visit(n); + if( n ) + { + assert( !this->replacement ); + this->replacement = mv$(n); + } } } @@ -382,7 +415,40 @@ struct CExpandExpr: auto saved = this->current_block; this->current_block = &node; - this->visit_vector(node.m_nodes); + + for( auto it = node.m_nodes.begin(); it != node.m_nodes.end(); ) + { + assert( it->get() ); + + if( auto* node_mac = dynamic_cast<::AST::ExprNode_Macro*>(it->get()) ) + { + Expand_Attrs((*it)->attrs(), AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, this->crate, *it); }); + if( !it->get() ) { + it = node.m_nodes.erase( it ); + continue ; + } + + assert(it->get() == node_mac); + + ::std::vector< ::AST::ExprNodeP> new_nodes; + this->visit_macro(*node_mac, &new_nodes); + + it = node.m_nodes.erase(it); + it = node.m_nodes.insert(it, ::std::make_move_iterator(new_nodes.begin()), ::std::make_move_iterator(new_nodes.end())); + // NOTE: Doesn't advance the iterator above, we want to re-visit the new node + } + else + { + this->visit(*it); + if( it->get() == nullptr ) { + it = node.m_nodes.erase( it ); + } + else { + ++ it; + } + } + } + this->current_block = saved; // HACK! Run Expand_Mod twice on local modules. |