diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index ffc9ca04..75b8cc0a 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -1996,14 +1996,19 @@ void Macro_InvokeRules_CountSubstUses(ParameterMappings& bound_tts, const ::std: while(const auto* ent_ptr = state.next_ent()) { DEBUG(*ent_ptr); - TU_IFLET(MacroExpansionEnt, (*ent_ptr), NamedValue, e, - if( e >> 30 ) { - } - else { + if(const auto* e = ent_ptr->opt_NamedValue()) { + switch(*e & ~NAMEDVALUE_VALMASK) + { + case 0: + case NAMEDVALUE_TY_IGNORE: // Increment a counter in `bound_tts` - bound_tts.inc_count(state.iterations(), e); + bound_tts.inc_count(state.iterations(), *e & NAMEDVALUE_VALMASK); + break; + case NAMEDVALUE_TY_MAGIC: + default: + break; } - ) + } } } @@ -2079,11 +2084,20 @@ Token MacroExpander::realGetToken() } } TU_ARMA(NamedValue, e) { - if( e >> 30 ) { - switch( e & 0x3FFFFFFF ) + switch(e & ~NAMEDVALUE_VALMASK) + { + default: + BUG(Span(), "Unknown macro metavar"); + case NAMEDVALUE_TY_IGNORE: { + auto* frag = m_mappings.get(m_state.iterations(), e & NAMEDVALUE_VALMASK); + ASSERT_BUG(this->point_span(), frag, "Cannot find '" << (e & NAMEDVALUE_VALMASK) << "' for " << m_state.iterations()); + // - Ignore + break; } + case NAMEDVALUE_TY_MAGIC: // NAMEDVALUE_TY_MAGIC + switch( e ) { // - XXX: Hack for $crate special name - case 0: + case NAMEDVALUE_MAGIC_CRATE: DEBUG("[" << m_log_index << "] Crate name hack"); if( m_crate_name == "" ) { @@ -2098,11 +2112,12 @@ Token MacroExpander::realGetToken() return Token(TOK_DOUBLE_COLON); } break; + case NAMEDVALUE_MAGIC_INDEX: default: BUG(Span(), "Unknown macro metavar"); } - } - else { + break; + case 0: { auto* frag = m_mappings.get(m_state.iterations(), e); ASSERT_BUG(this->point_span(), frag, "Cannot find '" << e << "' for " << m_state.iterations()); @@ -2126,6 +2141,7 @@ Token MacroExpander::realGetToken() return Token( *frag ); } } + } break; } } TU_ARMA(Loop, e) { diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp index 23213d75..95d64b59 100644 --- a/src/macro_rules/macro_rules.hpp +++ b/src/macro_rules/macro_rules.hpp @@ -36,6 +36,12 @@ TAGGED_UNION(MacroExpansionEnt, Token, }) ); extern ::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x); +static const unsigned int NAMEDVALUE_VALMASK = ((1<<30) - 1); +static const unsigned int NAMEDVALUE_TY_MAGIC = 1<<30; +static const unsigned int NAMEDVALUE_MAGIC_CRATE = NAMEDVALUE_TY_MAGIC | 0; +static const unsigned int NAMEDVALUE_MAGIC_INDEX = NAMEDVALUE_TY_MAGIC | 1; +static const unsigned int NAMEDVALUE_TY_IGNORE = 2<<30; +static const unsigned int NAMEDVALUE_TY_COUNT = 3<<30; /// Matching pattern entry struct MacroPatEnt diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 1b6b1b70..db1395d8 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -118,7 +118,6 @@ ::std::vector Parse_MacroRules_Pat(TokenStream& lex, enum eTokenTyp { case TOK_SQUARE_CLOSE: case TOK_PAREN_CLOSE: - case TOK_BRACE_CLOSE: ret.push_back( MacroPatEnt(lex.end_span(ps), TOK_DOLLAR) ); PUTBACK(tok, lex); break; @@ -382,9 +381,68 @@ ::std::vector Parse_MacroRules_Cont( DEBUG("joiner = " << Token(joiner) << ", controlling_loops = {" << controlling_loops << "}, content = " << content); ret.push_back( MacroExpansionEnt::make_Loop({ mv$(content), joiner, mv$(controlling_loops) }) ); } + // - `${operator(args}` - Extensions + else if( tok.type() == TOK_BRACE_OPEN ) + { + auto ident = lex.getTokenCheck(TOK_IDENT).ident().name; + if( ident == "ignore" ) { + lex.getTokenCheck(TOK_PAREN_OPEN); + GET_TOK(tok, lex); + auto name = tok.type() == TOK_IDENT ? tok.ident().name : RcString::new_interned(tok.to_str()); + lex.getTokenCheck(TOK_PAREN_CLOSE); + const auto* ns = state.find_name(name); + if( !ns ) { + TODO(lex.point_span(), "Handle ${ignore(" << name << ")} - Missing"); + } + + DEBUG("$" << name << " #" << ns->idx << " [" << ns->loops << "]"); + + // If the current loop depth is smaller than the stack for this variable, then error + if( loop_depth < ns->loops.size() ) { + ERROR(lex.point_span(), E0000, "Variable $" << name << " is still repeating at this depth (" << loop_depth << " < " << ns->loops.size() << ")"); + } + + if( var_usage_ptr ) { + var_usage_ptr->insert( ::std::make_pair(ns->idx, ContentLoopVariableUse(ns->loops)) ); + } + ret.push_back( MacroExpansionEnt(NAMEDVALUE_TY_IGNORE | ns->idx) ); + } + else if( ident == "count" ) { + lex.getTokenCheck(TOK_PAREN_OPEN); + GET_TOK(tok, lex); + auto name = tok.type() == TOK_IDENT ? tok.ident().name : RcString::new_interned(tok.to_str()); + lex.getTokenCheck(TOK_PAREN_CLOSE); + const auto* ns = state.find_name(name); + if( !ns ) { + TODO(lex.point_span(), "Handle ${count(" << name << ")} - Missing"); + } + + DEBUG("$" << name << " #" << ns->idx << " [" << ns->loops << "]"); + + // Can still be repeating + //// If the current loop depth is smaller than the stack for this variable, then error + //if( loop_depth < ns->loops.size() ) { + // ERROR(lex.point_span(), E0000, "Variable $" << name << " is still repeating at this depth (" << loop_depth << " < " << ns->loops.size() << ")"); + //} + + if( var_usage_ptr ) { + var_usage_ptr->insert( ::std::make_pair(ns->idx, ContentLoopVariableUse(ns->loops)) ); + } + ret.push_back( MacroExpansionEnt(NAMEDVALUE_TY_COUNT | ns->idx) ); + } + else if( ident == "index" ) { + lex.getTokenCheck(TOK_PAREN_OPEN); + lex.getTokenCheck(TOK_PAREN_CLOSE); + ret.push_back( MacroExpansionEnt(NAMEDVALUE_MAGIC_INDEX) ); + } + else { + TODO(lex.point_span(), "Handle ${" << ident << "...}"); + } + lex.getTokenCheck(TOK_BRACE_CLOSE); + } else if( tok.type() == TOK_RWORD_CRATE ) { - ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) ); + ret.push_back( MacroExpansionEnt(NAMEDVALUE_MAGIC_CRATE) ); } else if( tok.type() == TOK_IDENT || Token::type_is_rword(tok.type()) ) {