aboutsummaryrefslogtreecommitdiff
path: root/build2/scope.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'build2/scope.cxx')
-rw-r--r--build2/scope.cxx120
1 files changed, 106 insertions, 14 deletions
diff --git a/build2/scope.cxx b/build2/scope.cxx
index 0ef8de6..885a8d2 100644
--- a/build2/scope.cxx
+++ b/build2/scope.cxx
@@ -15,38 +15,127 @@ namespace build2
pair<lookup, size_t> scope::
find_original (const variable& var,
const target_type* tt, const string* tn,
- const target_type* gt, const string* gn) const
+ const target_type* gt, const string* gn,
+ size_t start_d) const
{
size_t d (0);
+ // Process target type/pattern-specific prepend/append values.
+ //
+ auto pre_app = [&var] (lookup& l,
+ const scope* s,
+ const target_type* tt, const string* tn,
+ const target_type* gt, const string* gn)
+ {
+ const value& v (*l);
+ assert ((v.extra == 1 || v.extra == 2) && v.type == nullptr);
+
+ // First we need to look for the stem value starting from the "next
+ // lookup point". That is, if we have the group, then from the
+ // s->target_vars (for the group), otherwise from s->vars, and then
+ // continuing looking in the outer scopes (for both target and group).
+ // Note that this may have to be repeated recursively, i.e., we may have
+ // prepents/appends in outer scopes. Also, if the value is for the
+ // group, then we shouldn't be looking for stem in the target's
+ // variables. In other words, once we "jump" to group, we stay there.
+ //
+ lookup stem (s->find_original (var, tt, tn, gt, gn, 2).first);
+
+ // Implementing proper caching is tricky so for now we are going to re-
+ // calculate the value every time. This is the same issue and the same
+ // planned solution as for the override cache (see below).
+ //
+ // Note: very similar logic as in the override cache population code
+ // below.
+ //
+ // @@ MT
+ //
+ value& cache (s->target_vars.cache[make_tuple (&v, tt, *tn)]);
+
+ // Un-typify the cache. This can be necessary, for example, if we are
+ // changing from one value-typed stem to another.
+ //
+ if (!stem.defined () || cache.type != stem->type)
+ {
+ cache = nullptr;
+ cache.type = nullptr; // Un-typify.
+ }
+
+ // Copy the stem.
+ //
+ if (stem.defined ())
+ cache = *stem;
+
+ // Typify the cache value in case there is no stem (we still want to
+ // prepend/append things in type-aware way).
+ //
+ if (cache.type == nullptr && var.type != nullptr)
+ typify (cache, *var.type, &var);
+
+ // Now prepend/append the value, unless it is NULL.
+ //
+ if (v)
+ {
+ if (v.extra == 1)
+ cache.prepend (names (cast<names> (v)), &var);
+ else
+ cache.append (names (cast<names> (v)), &var);
+ }
+
+ // Return cache as the resulting value but retain l.vars, so it looks as
+ // if the value came from s->target_vars.
+ //
+ l.value = &cache;
+ };
+
for (const scope* s (this); s != nullptr; )
{
if (tt != nullptr) // This started from the target.
{
bool f (!s->target_vars.empty ());
- ++d;
- if (f)
+ // Target.
+ //
+ if (++d >= start_d)
{
- lookup l (s->target_vars.find (*tt, *tn, var));
+ if (f)
+ {
+ lookup l (s->target_vars.find (*tt, *tn, var));
+
+ if (l.defined ())
+ {
+ if (l->extra != 0) // Prepend/append?
+ pre_app (l, s, tt, tn, gt, gn);
- if (l.defined ())
- return make_pair (move (l), d);
+ return make_pair (move (l), d);
+ }
+ }
}
- ++d;
- if (f && gt != nullptr)
+ // Group.
+ //
+ if (++d >= start_d)
{
- lookup l (s->target_vars.find (*gt, *gn, var));
+ if (f && gt != nullptr)
+ {
+ lookup l (s->target_vars.find (*gt, *gn, var));
+
+ if (l.defined ())
+ {
+ if (l->extra != 0) // Prepend/append?
+ pre_app (l, s, gt, gn, nullptr, nullptr);
- if (l.defined ())
- return make_pair (move (l), d);
+ return make_pair (move (l), d);
+ }
+ }
}
}
- ++d;
- if (const value* v = s->vars.find (var))
- return make_pair (lookup (v, &s->vars), d);
+ if (++d >= start_d)
+ {
+ if (const value* v = s->vars.find (var))
+ return make_pair (lookup (v, &s->vars), d);
+ }
switch (var.visibility)
{
@@ -302,6 +391,9 @@ namespace build2
// If there is a stem, set it as the initial value of the cache.
// Otherwise, start with a NULL value.
//
+ // Note: very similar logic as in the target type/pattern specific cache
+ // population code above.
+ //
// Un-typify the cache. This can be necessary, for example, if we are
// changing from one value-typed stem to another.