summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/expand/mod.cpp34
-rw-r--r--src/parse/common.hpp1
-rw-r--r--src/parse/expr.cpp138
3 files changed, 109 insertions, 64 deletions
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp
index 9537e5d3..55fd7d63 100644
--- a/src/expand/mod.cpp
+++ b/src/expand/mod.cpp
@@ -238,6 +238,8 @@ struct CExpandExpr:
LList<const AST::Module*> modstack;
::std::unique_ptr<::AST::ExprNode> replacement;
+ AST::ExprNode_Block* current_block = nullptr;
+
CExpandExpr(bool is_early, ::AST::Crate& crate, LList<const AST::Module*> ms):
is_early(is_early),
crate(crate),
@@ -297,6 +299,10 @@ struct CExpandExpr:
void visit(::AST::ExprNode_Macro& node) override
{
TRACE_FUNCTION_F("ExprNode_Macro - name = " << node.m_name);
+ if( node.m_name == "" ) {
+ return ;
+ }
+
auto& mod = this->cur_mod();
auto ttl = Expand_Macro(
is_early, crate, modstack, mod,
@@ -310,13 +316,24 @@ struct CExpandExpr:
SET_MODULE( (*ttl), mod );
// Reparse as expression / item
bool add_silence_if_end = false;
- auto newexpr = Parse_ExprBlockLine(*ttl, &add_silence_if_end);
- // 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);
+ ::std::unique_ptr< AST::Module> tmp_local_mod;
+ auto& local_mod_ptr = (this->current_block ? this->current_block->m_local_mod : tmp_local_mod);
+ auto newexpr = Parse_ExprBlockLine_WithItems(*ttl, local_mod_ptr, add_silence_if_end);
+ 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);
+ }
+ else
+ {
+ // TODO: Delete this node somehow? Or just leave it for later.
+ }
+ 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 = "";
@@ -327,7 +344,10 @@ struct CExpandExpr:
if( node.m_local_mod ) {
Expand_Mod(is_early, crate, modstack, node.m_local_mod->path(), *node.m_local_mod);
}
+ auto saved = this->current_block;
+ this->current_block = &node;
this->visit_vector(node.m_nodes);
+ this->current_block = saved;
}
void visit(::AST::ExprNode_Flow& node) override {
this->visit_nodelete(node, node.m_value);
diff --git a/src/parse/common.hpp b/src/parse/common.hpp
index f7168d33..c883c493 100644
--- a/src/parse/common.hpp
+++ b/src/parse/common.hpp
@@ -56,6 +56,7 @@ extern AST::ExprNodeP Parse_Expr0(TokenStream& lex);
extern AST::ExprNodeP Parse_ExprVal(TokenStream& lex);
extern AST::ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false);
extern AST::ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence);
+extern AST::ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::unique_ptr<AST::Module>& local_mod, bool& add_silence_if_end);
extern AST::ExprNodeP Parse_Stmt(TokenStream& lex);
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index 9d7748eb..774d7acc 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -24,6 +24,7 @@ static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){
#define NEWNODE(type, ...) mk_exprnodep(lex, new type(__VA_ARGS__))
//ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false); // common.hpp
+//ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::unique_ptr<AST::Module>& local_mod, bool& add_silence_if_end);
//ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence);
ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool *add_silence);
//ExprNodeP Parse_Stmt(TokenStream& lex); // common.hpp
@@ -58,82 +59,105 @@ ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe/*=false*/)
GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
+ while( LOOK_AHEAD(lex) != TOK_BRACE_CLOSE )
{
DEBUG("tok = " << tok);
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
+
+ // NOTE: Doc comments can appear within a function and apply to the function
+ // TODO: Use these attributes
+ while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
{
- item_attrs.push_back( Parse_MetaItem(lex) );
+ /*node_attrs.push_back(*/ Parse_MetaItem(lex) /*)*/;
GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
}
+ PUTBACK(tok, lex);
- switch(tok.type())
+ bool add_silence_if_end = false;
+ auto rv = Parse_ExprBlockLine_WithItems(lex, local_mod, add_silence_if_end);
+ if( rv )
{
- case TOK_CATTR_OPEN:
- // TODO: Handle `#![` by having a pointer to the parent item (e.g. function)'s attribute list.
- /*node_attrs.push_back(*/ Parse_MetaItem(lex) /*)*/;
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- break;
- // Items:
- case TOK_RWORD_PUB:
- ERROR(lex.getPosition(), E0000, "`pub` is useless within expression modules");
- case TOK_RWORD_TYPE:
- case TOK_RWORD_USE:
- case TOK_RWORD_EXTERN:
- case TOK_RWORD_CONST:
- case TOK_RWORD_STATIC:
- case TOK_RWORD_STRUCT:
- case TOK_RWORD_ENUM:
- case TOK_RWORD_TRAIT:
- case TOK_RWORD_IMPL:
- case TOK_RWORD_FN:
- case TOK_RWORD_MOD:
- PUTBACK(tok, lex);
- if( !local_mod ) {
- local_mod = lex.parse_state().get_current_mod().add_anon();
- }
- Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
- break;
- // 'unsafe' - Check if the next token isn't a `{`, if so it's an item. Otherwise, fall through
- case TOK_RWORD_UNSAFE:
- if( LOOK_AHEAD(lex) != TOK_BRACE_OPEN )
- {
- PUTBACK(tok, lex);
- if( !local_mod ) {
- local_mod = lex.parse_state().get_current_mod().add_anon();
- }
- Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
- break;
- }
- // fall
- default: {
- PUTBACK(tok, lex);
- bool add_silence_if_end = false;
- nodes.push_back(Parse_ExprBlockLine(lex, &add_silence_if_end));
- if( nodes.back() ) {
- nodes.back()->set_attrs( mv$(item_attrs) );
- }
- else {
- // TODO: Error if attribute on void expression?
- }
// Set to TRUE if there was no semicolon after a statement
if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE && add_silence_if_end )
{
DEBUG("expect_end == false, end of block");
- //nodes.push_back( NEWNODE(AST::ExprNode_Tuple, ::std::vector<ExprNodeP>()) );
yields_final_value = false;
- // NOTE: Would break out of the loop, but we're in a switch
- }
- break;
+ // Since the next token is TOK_BRACE_CLOSE, the loop will terminate
}
+ nodes.push_back( mv$(rv) );
+ }
+ else {
+ assert( !add_silence_if_end );
}
}
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
return NEWNODE( AST::ExprNode_Block, is_unsafe, yields_final_value, mv$(nodes), mv$(local_mod) );
}
+/// Parse a single line in a block, handling items added to the local module
+///
+/// - If an item was parsed, this returns an empty ExprNodeP
+ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::unique_ptr<AST::Module>& local_mod, bool& add_silence_if_end)
+{
+ Token tok;
+
+ AST::MetaItems item_attrs;
+ while( GET_TOK(tok, lex) == TOK_ATTR_OPEN )
+ {
+ item_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+
+ switch(tok.type())
+ {
+ // Items:
+ case TOK_RWORD_PUB:
+ ERROR(lex.getPosition(), E0000, "`pub` is useless within expression modules");
+ case TOK_RWORD_TYPE:
+ case TOK_RWORD_USE:
+ case TOK_RWORD_EXTERN:
+ case TOK_RWORD_CONST:
+ case TOK_RWORD_STATIC:
+ case TOK_RWORD_STRUCT:
+ case TOK_RWORD_ENUM:
+ case TOK_RWORD_TRAIT:
+ case TOK_RWORD_IMPL:
+ case TOK_RWORD_FN:
+ case TOK_RWORD_MOD:
+ PUTBACK(tok, lex);
+ if( !local_mod ) {
+ local_mod = lex.parse_state().get_current_mod().add_anon();
+ }
+ Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
+ return ExprNodeP();
+ // 'unsafe' - Check if the next token isn't a `{`, if so it's an item. Otherwise, fall through
+ case TOK_RWORD_UNSAFE:
+ if( LOOK_AHEAD(lex) != TOK_BRACE_OPEN )
+ {
+ PUTBACK(tok, lex);
+ if( !local_mod ) {
+ local_mod = lex.parse_state().get_current_mod().add_anon();
+ }
+ Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
+ return ExprNodeP();
+ }
+ // fall
+ default: {
+ PUTBACK(tok, lex);
+ auto rv = Parse_ExprBlockLine(lex, &add_silence_if_end);
+ if( rv ) {
+ rv->set_attrs( mv$(item_attrs) );
+ }
+ else if( item_attrs.m_items.size() > 0 ) {
+ // TODO: Is this an error? - Attributes on a expression that didn't yeild a node.
+ }
+ else {
+ }
+ return rv;
+ } break;
+ }
+}
+
/// Parse a single line from a block
///
/// Handles: