summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-09-26 14:03:18 +0800
committerJohn Hodge <tpg@mutabah.net>2016-09-26 14:03:18 +0800
commitfbba1b4d8412e70e7114326d0517a13b1d4bc7a2 (patch)
tree477e097b9dd55780599abe23b083cf1bc4d5a05a /src
parent04f2da9e198abf8e96cd3abb3782f2bfeae3c8f5 (diff)
downloadmrust-fbba1b4d8412e70e7114326d0517a13b1d4bc7a2.tar.gz
macro_rules - Extend logic to determine if a loop should be entered to handle $()* at the start
Diffstat (limited to 'src')
-rw-r--r--src/macro_rules/eval.cpp117
-rw-r--r--src/parse/expr.cpp12
2 files changed, 112 insertions, 17 deletions
diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp
index c6dfd72e..8b698ac1 100644
--- a/src/macro_rules/eval.cpp
+++ b/src/macro_rules/eval.cpp
@@ -125,6 +125,9 @@ class MacroPatternStream
::std::vector<SimplePatEnt> m_stack;
unsigned int m_skip_count;
+
+ bool m_break_if_not = false;
+ bool m_condition_fired = false;
public:
MacroPatternStream(const ::std::vector<MacroPatEnt>& pattern):
m_pattern(&pattern),
@@ -143,6 +146,14 @@ public:
private:
SimplePatEnt emit_loop_start(const MacroPatEnt& pat);
+
+ SimplePatEnt emit_seq(SimplePatEnt v1, SimplePatEnt v2) {
+ assert( m_stack.empty() );
+ m_stack.push_back( mv$(v2) );
+ return v1;
+ }
+
+ void break_loop();
};
// === Prototypes ===
@@ -179,7 +190,7 @@ void ParameterMappings::insert(unsigned int name_index, const ::std::vector<unsi
}
else {
if( e.size() > iter ) {
- DEBUG("ERROR: Iterations ran backwards?");
+ DEBUG("ERROR: Iterations ran backwards? - " << e.size() << " > " << iter);
}
}
layer = &e[iter];
@@ -240,6 +251,10 @@ unsigned int ParameterMappings::count_in(const ::std::vector<unsigned int>& iter
return 0;
),
(Nested,
+ if( iter >= e.size() ) {
+ DEBUG("Counting value for an iteration index it doesn't have - " << iter << " >= " << e.size());
+ return 0;
+ }
layer = &e[iter];
)
)
@@ -284,13 +299,14 @@ SimplePatEnt MacroPatternStream::next()
return rv;
}
- m_skip_count = 0;
-
- /*
if( m_break_if_not && ! m_condition_fired ) {
// Break out of the current loop then continue downwards.
+ break_loop();
}
- */
+
+ m_skip_count = 0;
+ m_break_if_not = false;
+ m_condition_fired = false;
const MacroPatEnt* parent_pat = nullptr;
decltype(m_pattern) parent_ents = nullptr;
@@ -364,14 +380,18 @@ SimplePatEnt MacroPatternStream::next()
DEBUG("MAGIC: Reverse conditions for case where sep==next");
// > Mark to skip the next token after the end of the loop
m_skip_count = 1;
- // - Yeild `EXPECT sep` and `IF NOT start BREAK`
- m_stack.push_back( SimplePatEnt::make_IfTok({ false, ents->at(0).tok.clone() }) );
- return SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() );
+ // - Yeild `EXPECT sep` then `IF NOT start BREAK`
+ return emit_seq(
+ SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() ),
+ SimplePatEnt::make_IfTok({ false, ents->at(0).tok.clone() })
+ );
}
}
// - Yeild `IF NOT sep BREAK` and `EXPECT sep`
- m_stack.push_back( SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() ) );
- return SimplePatEnt::make_IfTok({ false, parent_pat->tok.clone() });
+ return emit_seq(
+ SimplePatEnt::make_IfTok({ false, parent_pat->tok.clone() }),
+ SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() )
+ );
}
}
else
@@ -386,23 +406,75 @@ SimplePatEnt MacroPatternStream::next()
SimplePatEnt MacroPatternStream::emit_loop_start(const MacroPatEnt& pat)
{
// Find the next non-loop pattern to control if this loop should be entered
+ ::std::vector<const MacroPatEnt*> m_entry_pats;
+
+ const auto* parent_subpats = &pat.subpats;
const auto* entry_pat = &pat.subpats.at(0);
while( entry_pat->type == MacroPatEnt::PAT_LOOP ) {
+ if( entry_pat->name == "*" ) {
+ if( parent_subpats->size() > 1 ) {
+ if( parent_subpats->at(1).type == MacroPatEnt::PAT_LOOP ) {
+ // TODO: Recurse here
+ // This case is either: Direct recurse, or recurse+next pattern (index 2 instead of 1)
+ DEBUG("TODO TODO: Handle case where an optional loop is folled by another loop.");
+ }
+ else {
+ m_entry_pats.push_back( &parent_subpats->at(1) );
+ }
+ }
+ else {
+ // Only entry, no second condtiion present
+ }
+ }
+ else {
+ // Always entered, so entry condition is the inner
+ }
+ parent_subpats = &entry_pat->subpats;
entry_pat = &entry_pat->subpats.at(0);
}
// - TODO: What if there's multiple tokens that can be used to enter the loop?
// > `$( $(#[...])* foo)*` should enter based on `#` and `foo`
// > Requires returning multiple controllers and requiring that at least one succeed
-
- // Emit an if based on it
- if( entry_pat->type == MacroPatEnt::PAT_TOKEN )
- return SimplePatEnt::make_IfTok({ false, entry_pat->tok.clone() });
+
+ struct H {
+ static SimplePatEnt get_if(bool flag, const MacroPatEnt& mpe) {
+ if( mpe.type == MacroPatEnt::PAT_TOKEN )
+ return SimplePatEnt::make_IfTok({ flag, mpe.tok.clone() });
+ else
+ return SimplePatEnt::make_IfPat({ flag, mpe.type });
+ }
+ };
+
+ if( m_entry_pats.size() > 0 )
+ {
+ DEBUG("Multiple entry possibilities, reversing condition");
+ m_break_if_not = true;
+ for(auto pat_ptr : m_entry_pats)
+ {
+ m_stack.push_back( H::get_if(true, *pat_ptr) );
+ }
+ return H::get_if(true, *entry_pat);
+ }
else
- return SimplePatEnt::make_IfPat({ false, entry_pat->type });
+ {
+ // Emit an if based on it
+ return H::get_if(false, *entry_pat);
+ }
}
void MacroPatternStream::if_succeeded()
{
+ if( m_break_if_not )
+ {
+ m_condition_fired = true;
+ }
+ else
+ {
+ break_loop();
+ }
+}
+void MacroPatternStream::break_loop()
+{
DEBUG("- Break out of loop, m_skip_count = " << m_skip_count);
// Break out of an active loop (pop level and increment parent level)
assert( m_pos.size() >= 1 );
@@ -503,7 +575,16 @@ bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type)
case MacroPatEnt::PAT_IDENT:
return LOOK_AHEAD(lex) == TOK_IDENT;
case MacroPatEnt::PAT_TT:
- return LOOK_AHEAD(lex) != TOK_EOF;
+ switch(LOOK_AHEAD(lex))
+ {
+ case TOK_EOF:
+ case TOK_PAREN_CLOSE:
+ case TOK_BRACE_CLOSE:
+ case TOK_SQUARE_CLOSE:
+ return false;
+ default:
+ return true;
+ }
case MacroPatEnt::PAT_PATH:
return is_token_path( LOOK_AHEAD(lex) );
case MacroPatEnt::PAT_TYPE:
@@ -737,7 +818,8 @@ bool Macro_HandlePattern(TokenStream& lex, const MacroPatEnt& pat, ::std::vector
}
if( arm_pats.size() == 0 ) {
- ERROR(sp, E0000, "No rules expected " << lex.getToken());
+ auto tok = lex.getToken();
+ ERROR(tok.get_pos(), E0000, "No rules expected " << tok);
}
// 3. Check that all remaining arms are the same pattern.
for(unsigned int i = 1; i < arm_pats.size(); i ++)
@@ -832,6 +914,7 @@ 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 ) {
}
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index 46be8e63..c632ed55 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -1219,8 +1219,20 @@ TokenTree Parse_TT(TokenStream& lex, bool unwrapped)
case TOK_BRACE_OPEN:
closer = TOK_BRACE_CLOSE;
break;
+ // HACK! mrustc parses #[ and #![ as composite tokens
+ // TODO: Split these into their component tokens.
+ case TOK_ATTR_OPEN:
+ case TOK_CATTR_OPEN:
+ if( unwrapped )
+ throw ParseError::Unexpected(lex, tok);
+ closer = TOK_SQUARE_CLOSE;
+ break;
+
case TOK_EOF:
case TOK_NULL:
+ case TOK_PAREN_CLOSE:
+ case TOK_SQUARE_CLOSE:
+ case TOK_BRACE_CLOSE:
throw ParseError::Unexpected(lex, tok);
default:
return TokenTree( mv$(tok) );