diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-01-15 11:03:06 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-01-15 11:03:06 +0200 |
commit | df50091259a34fa4718f38c0e3b7b64f6e2469ac (patch) | |
tree | 2d3172068f9ea1f4ecc6599192c42ac4172d9cfc /build/algorithm.cxx | |
parent | c59ce78f409db8bb53042380903c8ece8b8fbd28 (diff) |
Implement rule ambiguity detection
Also establish the infrastructure for rule hinting
Diffstat (limited to 'build/algorithm.cxx')
-rw-r--r-- | build/algorithm.cxx | 105 |
1 files changed, 96 insertions, 9 deletions
diff --git a/build/algorithm.cxx b/build/algorithm.cxx index 1d7f215..a4160ef 100644 --- a/build/algorithm.cxx +++ b/build/algorithm.cxx @@ -84,29 +84,116 @@ namespace build tt != nullptr && !t.recipe (); tt = tt->base) { - for (auto rs (rules.equal_range (tt->id)); - rs.first != rs.second; - ++rs.first) + auto i (rules.find (tt->id)); + + if (i == rules.end ()) // No rules registered for this target type. + continue; + + const auto& rules (i->second); // Name map. + + string hint; // @@ TODO + bool single; + + auto rs (hint.empty () + ? make_pair (rules.begin (), rules.end ()) + : rules.find (hint)); + + for (auto i (rs.first); i != rs.second;) { - const rule& ru (rs.first->second); + const string& n (i->first); + const rule& ru (i->second); - recipe re; + if (i++ == rs.first) + single = (i == rs.second); + recipe re; + string h (hint); { auto g ( make_exception_guard ( - [] (target& t) + [] (target& t, const string& n) { - cerr << "info: while matching a rule for target " << t << endl; + cerr << "info: while matching rule " << n + << " for target " << t << endl; }, - t)); + t, n)); - re = ru.match (t); + // If the rule matches, then it updates the hint with the one we + // need to use when checking for ambiguity. + // + re = ru.match (t, single, h); } if (re) { t.recipe (re); + + // If the returned hint is more "general" than what we had, + // then narrow it back down. + // + if (h < hint) + h = hint; + + // Do the ambiguity test unless it is an unambiguous match (the + // hint is the rule's full name). + // + if (h == n) + break; + + auto rs1 (h == hint + ? make_pair (i, rs.second) // Continue iterating. + : rules.find (h)); + + bool ambig (false); + + // See if any other rules match. + // + for (auto i (rs1.first); i != rs1.second; ++i) + { + const string& n1 (i->first); + const rule& ru1 (i->second); + + string h1 (h); + { + auto g ( + make_exception_guard ( + [] (target& t, const string& n1) + { + cerr << "info: while matching rule " << n1 + << " for target " << t << endl; + }, + t, n1)); + + re = ru1.match (t, false, h1); + } + + if (re) + { + // A subsequent rule cannot return a more specific hint. + // Remember, the hint returning mechanism is here to + // indicate that only a class of rules that perform a + // similar rule chaining transformation may apply (e.g., + // cxx.gnu and cxx.clang). + // + assert (h1 <= h); + + if (!ambig) + { + cerr << "error: multiple rules matching target " << t << endl; + cerr << "info: rule " << n << " matches" << endl; + ambig = true; + } + + cerr << "info: rule " << n1 << " also matches" << endl; + } + } + + if (ambig) + { + cerr << "info: use rule hint to disambiguate this match" << endl; + throw error (); + } + break; } } |