aboutsummaryrefslogtreecommitdiff
path: root/build/algorithm.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-01-15 11:03:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-01-15 11:03:06 +0200
commitdf50091259a34fa4718f38c0e3b7b64f6e2469ac (patch)
tree2d3172068f9ea1f4ecc6599192c42ac4172d9cfc /build/algorithm.cxx
parentc59ce78f409db8bb53042380903c8ece8b8fbd28 (diff)
Implement rule ambiguity detection
Also establish the infrastructure for rule hinting
Diffstat (limited to 'build/algorithm.cxx')
-rw-r--r--build/algorithm.cxx105
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;
}
}