summaryrefslogtreecommitdiff
path: root/src/expand/mod.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/expand/mod.cpp')
-rw-r--r--src/expand/mod.cpp120
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.