aboutsummaryrefslogtreecommitdiff
path: root/build2/variable.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-01-30 11:12:25 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-02-13 12:42:41 +0200
commitb262d2c9c56eed18d043dccefac02b54a6ae2f95 (patch)
tree010e5c6cce042e0fbf25817a62659d251c220acf /build2/variable.cxx
parentf93038fbee1631b95922b0742e0fd00fa8dae02e (diff)
Implement pattern-based variable typing, tighten variable type update
Diffstat (limited to 'build2/variable.cxx')
-rw-r--r--build2/variable.cxx183
1 files changed, 129 insertions, 54 deletions
diff --git a/build2/variable.cxx b/build2/variable.cxx
index bbe08d0..8695623 100644
--- a/build2/variable.cxx
+++ b/build2/variable.cxx
@@ -906,23 +906,82 @@ namespace build2
// variable_pool
//
- const variable& variable_pool::
- insert (string n)
+ void variable_pool::
+ update (variable& var,
+ const build2::value_type* t,
+ const variable_visibility* v,
+ const bool* o) const
{
- assert (!global_ || phase == run_phase::load);
+ // Check overridability (all overrides, if any, should already have
+ // been entered (see context.cxx:reset()).
+ //
+ if (var.override != nullptr && (o == nullptr || !*o))
+ fail << "variable " << var.name << " cannot be overridden";
- // We are not overriding anything so skip the insert_() checks.
+ bool ut (t != nullptr && var.type != t);
+ bool uv (v != nullptr && var.visibility != *v);
+
+ // In the global pool existing variables can only be updated during
+ // serial load.
//
- auto p (
- insert (
- variable {move (n), nullptr, nullptr, variable_visibility::normal}));
+ assert (!global_ || !(ut || uv) || model_lock == nullptr);
- const variable& r (p.first->second);
+ // Update type?
+ //
+ if (ut)
+ {
+ assert (var.type == nullptr);
+ var.type = t;
+ }
- if (r.override != nullptr)
- fail << "variable " << r.name << " cannot be overridden";
+ // Change visibility? While this might at first seem like a bad idea,
+ // it can happen that the variable lookup happens before any values
+ // were set, in which case the variable will be entered with the
+ // default visibility.
+ //
+ if (uv)
+ {
+ assert (var.visibility == variable_visibility::normal); // Default.
+ var.visibility = *v;
+ }
+ }
- return r;
+ static bool
+ match_pattern (const string& n, const string& p, const string& s, bool multi)
+ {
+ size_t nn (n.size ()), pn (p.size ()), sn (s.size ());
+
+ if (nn < pn + sn + 1)
+ return false;
+
+ if (pn != 0)
+ {
+ if (n.compare (0, pn, p) != 0)
+ return false;
+ }
+
+ if (sn != 0)
+ {
+ if (n.compare (nn - sn, sn, s) != 0)
+ return false;
+ }
+
+ // Make sure the stem is a single name unless instructed otherwise.
+ //
+ return multi || string::traits_type::find (n.c_str () + pn,
+ nn - pn - sn,
+ '.') == nullptr;
+ }
+
+ static inline void
+ merge_pattern (const variable_pool::pattern& p,
+ const build2::value_type*& t,
+ const variable_visibility*& v,
+ const bool*& o)
+ {
+ if (t == nullptr) t = p.type; else assert ( t == p.type);
+ if (v == nullptr) v = &p.visibility; else assert (*v == p.visibility);
+ if (o == nullptr) o = &p.overridable; else assert (*o == p.overridable);
}
const variable& variable_pool::
@@ -933,6 +992,20 @@ namespace build2
{
assert (!global_ || phase == run_phase::load);
+ // Apply pattern.
+ //
+ if (n.find ('.') != string::npos)
+ {
+ for (const pattern& p: reverse_iterate (patterns_))
+ {
+ if (match_pattern (n, p.prefix, p.suffix, p.multi))
+ {
+ merge_pattern (p, t, v, o);
+ break;
+ }
+ }
+ }
+
auto p (
insert (
variable {
@@ -941,61 +1014,63 @@ namespace build2
nullptr,
v != nullptr ? *v : variable_visibility::normal}));
- const variable& r (p.first->second);
+ variable& r (p.first->second);
if (!p.second)
{
- // Check overridability (all overrides, if any, should already have
- // been entered (see context.cxx:reset()).
- //
- if (r.override != nullptr && (o == nullptr || !*o))
- fail << "variable " << r.name << " cannot be overridden";
+ if (t != nullptr || v != nullptr || o != nullptr)
+ update (r, t, v, o); // Not changing the key.
+ else
+ if (r.override != nullptr)
+ fail << "variable " << r.name << " cannot be overridden";
+ }
- bool ut (t != nullptr && r.type != t);
- bool uv (v != nullptr && r.visibility != *v);
+ return r;
+ }
- // In the global pool existing variables can only be updated during
- // serial load.
- //
- /*
- @@ MT
+ void variable_pool::
+ insert_pattern (const string& p,
+ const build2::value_type* t,
+ bool o,
+ variable_visibility v)
+ {
+ size_t pn (p.size ());
- if (global_)
- {
- //assert (!(ut || uv) || model_lock == nullptr);
+ size_t w (p.find ('*'));
+ assert (w != string::npos);
- if (model_lock != nullptr)
- {
- if (ut)
- text << r.name << " type update during exclusive load";
+ bool multi (w + 1 != pn && p[w + 1] == '*');
- if (uv)
- text << r.name << " visibility update during exclusive load";
- }
- }
- */
+ // Extract prefix and suffix.
+ //
+ string pfx, sfx;
- // Update type?
- //
- if (ut)
- {
- assert (r.type == nullptr);
- const_cast<variable&> (r).type = t; // Not changing the key.
- }
+ if (w != 0)
+ {
+ assert (p[w - 1] == '.' && w != 1);
+ pfx.assign (p, 0, w);
+ }
- // Change visibility? While this might at first seem like a bad idea,
- // it can happen that the variable lookup happens before any values
- // were set, in which case the variable will be entered with the
- // default visibility.
- //
- if (uv)
- {
- assert (r.visibility == variable_visibility::normal); // Default.
- const_cast<variable&> (r).visibility = *v; // Not changing the key.
- }
+ w += multi ? 2 : 1; // First suffix character.
+ size_t sn (pn - w); // Suffix length.
+
+ if (sn != 0)
+ {
+ assert (p[w] == '.' && sn != 1);
+ sfx.assign (p, w, sn);
}
- return r;
+ // Apply retrospectively to existing variables.
+ //
+ for (auto& p: map_)
+ {
+ variable& var (p.second);
+
+ if (match_pattern (var.name, pfx, sfx, multi))
+ update (var, t, &v, &o); // Not changing the key.
+ }
+
+ patterns_.push_back (pattern {move (pfx), move (sfx), multi, t, v, o});
}
variable_pool variable_pool::instance (true);