summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/macro_rules/eval.cpp52
-rw-r--r--src/macro_rules/parse.cpp5
2 files changed, 52 insertions, 5 deletions
diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp
index fc54616e..41a96bb2 100644
--- a/src/macro_rules/eval.cpp
+++ b/src/macro_rules/eval.cpp
@@ -761,6 +761,7 @@ namespace
::std::vector<size_t> m_offsets;
size_t m_active_offset;
+ Token m_faked_next;
size_t m_consume_count;
public:
TokenStreamRO(const TokenTree& tt):
@@ -798,6 +799,11 @@ namespace
const Token& next_tok() const {
static Token eof_token = TOK_EOF;
+ if( m_faked_next.type() != TOK_NULL )
+ {
+ return m_faked_next;
+ }
+
if( m_offsets.empty() && m_active_offset == m_tt.size() )
{
//DEBUG(m_consume_count << " " << eof_token << "(EOF)");
@@ -815,6 +821,12 @@ namespace
}
void consume()
{
+ if( m_faked_next.type() != TOK_NULL )
+ {
+ m_faked_next = Token(TOK_NULL);
+ return ;
+ }
+
if( m_offsets.empty() && m_active_offset == m_tt.size() )
throw ::std::runtime_error("Attempting to consume EOS");
DEBUG(m_consume_count << " " << next_tok());
@@ -829,7 +841,7 @@ namespace
// If reached the end of a tree...
if(m_active_offset == cur_tree->size())
{
- // If the end of the root is reached, return (leaving the state indicating EOS0
+ // If the end of the root is reached, return (leaving the state indicating EOS)
if( m_offsets.empty() )
return ;
// Pop and continue
@@ -850,6 +862,11 @@ namespace
}
}
}
+ void consume_and_push(eTokenType ty)
+ {
+ consume();
+ m_faked_next = Token(ty);
+ }
// Consumes if the current token is `ty`, otherwise doesn't and returns false
bool consume_if(eTokenType ty)
@@ -919,7 +936,20 @@ namespace
}
else if( lex.next() == TOK_GT || lex.next() == TOK_DOUBLE_GT )
{
- level -= (lex.next() == TOK_DOUBLE_GT ? 2 : 1);
+ assert(level > 0);
+ if( lex.next() == TOK_DOUBLE_GT )
+ {
+ if( level == 1 )
+ {
+ lex.consume_and_push(TOK_GT);
+ return true;
+ }
+ level -= 2;
+ }
+ else
+ {
+ level -= 1;
+ }
if( level == 0 )
break;
}
@@ -1100,6 +1130,9 @@ namespace
return true;
}
+ if( lex.consume_if(TOK_INTERPOLATED_PATTERN) )
+ return true;
+
for(;;)
{
if( lex.consume_if(TOK_UNDERSCORE) )
@@ -1115,6 +1148,13 @@ namespace
if( lex.next() == TOK_BRACE_OPEN ) {
return consume_tt(lex);
}
+ else if( lex.next() == TOK_PAREN_OPEN ) {
+ return consume_tt(lex);
+ }
+ else if( lex.next() == TOK_EXCLAM ) {
+ lex.consume();
+ return consume_tt(lex);
+ }
break;
case TOK_RWORD_BOX:
lex.consume();
@@ -1174,12 +1214,14 @@ namespace
{
do
{
+ if( lex.next() == TOK_PIPE )
+ break;
consume_pat(lex);
if(lex.consume_if(TOK_COLON))
{
consume_type(lex);
}
- } while(lex.next() == TOK_COMMA);
+ } while(lex.consume_if(TOK_COMMA));
if( !lex.consume_if(TOK_PIPE) )
return false;
}
@@ -1436,6 +1478,8 @@ namespace
case TOK_EXCLAM_EQUAL:
case TOK_DOUBLE_AMP:
case TOK_DOUBLE_PIPE:
+ case TOK_DOUBLE_DOT:
+ case TOK_TRIPLE_DOT:
lex.consume();
break;
case TOK_EQUAL:
@@ -2321,7 +2365,7 @@ Token MacroExpander::realGetToken()
{
const auto& ent = *next_ent_ptr;
TU_IFLET(MacroExpansionEnt, ent, Token, e,
- return e;
+ return e.clone();
)
else if( ent.is_NamedValue() ) {
const auto& e = ent.as_NamedValue();
diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp
index f5b0f0e4..b3b1014e 100644
--- a/src/macro_rules/parse.cpp
+++ b/src/macro_rules/parse.cpp
@@ -212,7 +212,10 @@ public:
// TODO: `error-chain`'s quick_error macro has an arm which refers to an undefined metavar.
// - Maybe emit a warning and use a marker index.
WARNING(lex.point_span(), W0000, "Macro variable $" << name << " not found");
- idx = (1<<16)-1; // NOTE: Encoded as a u16
+ // Emit the literal $ <name>
+ ret.push_back( MacroExpansionEnt(Token(TOK_DOLLAR)) );
+ ret.push_back( MacroExpansionEnt(mv$(tok)) );
+ continue ;
}
if( var_set_ptr ) {
var_set_ptr->insert( ::std::make_pair(idx,true) );