summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir/deserialise.cpp9
-rw-r--r--src/hir/serialise.cpp8
-rw-r--r--src/macro_rules/eval.cpp12
-rw-r--r--src/macro_rules/macro_rules.hpp3
-rw-r--r--src/macro_rules/parse.cpp24
5 files changed, 34 insertions, 22 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index 1cf5f0e0..08662fe2 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -338,10 +338,13 @@ namespace {
case 2: {
auto entries = deserialise_vec_c< ::MacroExpansionEnt>( [&](){ return deserialise_macroexpansionent(); } );
auto joiner = deserialise_token();
- ::std::set<unsigned int> variables;
+ ::std::map<unsigned int, bool> variables;
size_t n = read_count();
- while(n--)
- variables.insert( static_cast<unsigned int>(read_count()) );
+ while(n--) {
+ auto idx = static_cast<unsigned int>(read_count());
+ bool flag = read_bool();
+ variables.insert( ::std::make_pair(idx, flag) );
+ }
return ::MacroExpansionEnt::make_Loop({
mv$(entries), mv$(joiner), mv$(variables)
});
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index 832177e1..a45759b8 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -435,10 +435,12 @@ namespace {
write_tag(2);
serialise_vec(e.entries);
serialise(e.joiner);
- // ::std::set<unsigned int>
+ // ::std::map<unsigned int,bool>
write_count(e.variables.size());
- for(const auto& var : e.variables)
- write_count(var);
+ for(const auto& var : e.variables) {
+ write_count(var.first);
+ write_bool(var.second);
+ }
)
)
}
diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp
index 66382ed7..9af766b6 100644
--- a/src/macro_rules/eval.cpp
+++ b/src/macro_rules/eval.cpp
@@ -731,7 +731,7 @@ bool Macro_HandlePattern(TokenStream& lex, const MacroPatEnt& pat, ::std::vector
/// Parse the input TokenTree according to the `macro_rules!` patterns and return a token stream of the replacement
::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input, AST::Module& mod)
{
- TRACE_FUNCTION_F(name);
+ TRACE_FUNCTION_F("'" << name << "', " << input);
ParameterMappings bound_tts;
unsigned int rule_index = Macro_InvokeRules_MatchPattern(rules, mv$(input), mod, bound_tts);
@@ -1052,14 +1052,16 @@ const MacroExpansionEnt* MacroExpandState::next_ent()
(Loop,
// 1. Get number of times this will repeat (based on the next iteration count)
unsigned int num_repeats = 0;
- for(const auto idx : e.variables) {
- unsigned int this_repeats = m_mappings.count_in(m_iterations, idx);
- // If a variable doesn't have data, don't loop
- if( this_repeats == 0 ) {
+ // TODO: Have a flag for each of these that indicates if it's a definitive controller? (I.e. if zero, don't loop)
+ for(const auto& var : e.variables) {
+ unsigned int this_repeats = m_mappings.count_in(m_iterations, var.first);
+ // If a variable doesn't have data and it's a required controller, don't loop
+ if( this_repeats == 0 && var.second ) {
num_repeats = 0;
break;
}
// TODO: Ideally, all variables would have the same repeat count.
+ // Options: 0 (optional), 1 (higher), N (all equal)
if( this_repeats > num_repeats )
num_repeats = this_repeats;
}
diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp
index 550068b8..ddf11dcb 100644
--- a/src/macro_rules/macro_rules.hpp
+++ b/src/macro_rules/macro_rules.hpp
@@ -31,7 +31,8 @@ TAGGED_UNION_EX(MacroExpansionEnt, (: public Serialisable), Token, (
/// Token used to join iterations
Token joiner;
/// List of variables within this loop that control its iteration count
- ::std::set< unsigned int> variables;
+ /// Boolean is true if the variable will be unconditionally expanded
+ ::std::map< unsigned int, bool> variables;
})
),
(),
diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp
index 56fa6518..dce01c86 100644
--- a/src/macro_rules/parse.cpp
+++ b/src/macro_rules/parse.cpp
@@ -128,7 +128,7 @@ public:
TokenStream& lex,
enum eTokenType open, enum eTokenType close,
const ::std::vector< ::std::string>& var_names,
- ::std::set<unsigned int>* var_set_ptr=nullptr
+ ::std::map<unsigned int,bool>* var_set_ptr=nullptr
)
{
TRACE_FUNCTION;
@@ -166,15 +166,10 @@ public:
// `$(`
if( tok.type() == TOK_PAREN_OPEN )
{
- ::std::set<unsigned int> var_set;
+ ::std::map<unsigned int, bool> var_set;
auto content = Parse_MacroRules_Cont(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, var_names, &var_set);
// ^^ The above will eat the PAREN_CLOSE
- if( var_set_ptr ) {
- for(const auto& v : var_set)
- var_set_ptr->insert( v );
- }
-
GET_TOK(tok, lex);
enum eTokenType joiner = TOK_NULL;
if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR )
@@ -182,12 +177,21 @@ public:
joiner = tok.type();
GET_TOK(tok, lex);
}
+ bool is_optional = (tok.type() == TOK_STAR);
+ if( var_set_ptr ) {
+ for(const auto& v : var_set) {
+ // If `is_optional`: Loop may not be expanded, so var_not_opt=false
+ // Else, inherit
+ bool var_not_opt = (is_optional ? false : v.second);
+ var_set_ptr->insert( ::std::make_pair(v.first, var_not_opt) ).first->second |= var_not_opt;
+ }
+ }
DEBUG("joiner = " << Token(joiner) << ", content = " << content);
switch(tok.type())
{
- case TOK_STAR:
case TOK_PLUS:
- // TODO: Ensure that +/* match up
+ case TOK_STAR:
+ // TODO: Ensure that +/* match up?
ret.push_back( MacroExpansionEnt({mv$(content), joiner, mv$(var_set)}) );
break;
default:
@@ -202,7 +206,7 @@ public:
if( idx == var_names.size() )
ERROR(lex.getPosition(), E0000, "Macro variable $" << tok.str() << " not found");
if( var_set_ptr ) {
- var_set_ptr->insert( idx );
+ var_set_ptr->insert( ::std::make_pair(idx,true) );
}
ret.push_back( MacroExpansionEnt(idx) );
}