aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/context2
-rw-r--r--build2/parser.cxx18
-rw-r--r--build2/target2
-rw-r--r--build2/types4
-rw-r--r--build2/variable38
-rw-r--r--build2/variable.cxx77
-rw-r--r--build2/variable.ixx20
7 files changed, 118 insertions, 43 deletions
diff --git a/build2/context b/build2/context
index 2f0a76f..c443a7a 100644
--- a/build2/context
+++ b/build2/context
@@ -24,7 +24,7 @@ namespace build2
// The phase can only be changed during serial or exclusive execution
// (see below).
//
- extern enum class run_phase {load, search_match, execute} phase;
+ extern run_phase phase;
// The build system model (internal state) is protected at the top level by
// the model mutex. During serial execution the model mutex is unlocked.
diff --git a/build2/parser.cxx b/build2/parser.cxx
index af6a6f5..7f6b940 100644
--- a/build2/parser.cxx
+++ b/build2/parser.cxx
@@ -1658,13 +1658,17 @@ namespace build2
// be the same. Also check that the requested value type doesn't conflict
// with the variable type.
//
- if (type != nullptr &&
- var != nullptr &&
- var->type != nullptr &&
- var->type != type)
+ if (var != nullptr && var->type != nullptr)
{
- fail (l) << "conflicting variable " << var->name << " type "
- << var->type->name << " and value type " << type->name;
+ if (type == nullptr)
+ {
+ type = var->type;
+ }
+ else if (var->type != type)
+ {
+ fail (l) << "conflicting variable " << var->name << " type "
+ << var->type->name << " and value type " << type->name;
+ }
}
// What if both LHS and RHS are typed? For now we do lexical conversion:
@@ -1682,7 +1686,7 @@ namespace build2
{
// Only consider RHS type if there is no explicit or variable type.
//
- if (type == nullptr && (var == nullptr || var->type == nullptr))
+ if (type == nullptr)
{
type = rhs.type;
rhs_type = true;
diff --git a/build2/target b/build2/target
index 8733a59..30dffab 100644
--- a/build2/target
+++ b/build2/target
@@ -550,7 +550,7 @@ namespace build2
public:
target (dir_path d, dir_path o, string n, optional<string> e)
: dir (move (d)), out (move (o)), name (move (n)), ext (move (e)),
- vars (true) // Global.
+ vars (false) // Note: not global.
{}
};
diff --git a/build2/types b/build2/types
index daf10d3..7f39274 100644
--- a/build2/types
+++ b/build2/types
@@ -159,6 +159,10 @@ namespace build2
// <butl/target-triplet>
//
using butl::target_triplet;
+
+ // See context.
+ //
+ enum class run_phase {load, search_match, execute};
}
// In order to be found (via ADL) these have to be either in std:: or in
diff --git a/build2/variable b/build2/variable
index 0df28d8..6e20a9c 100644
--- a/build2/variable
+++ b/build2/variable
@@ -1011,26 +1011,37 @@ namespace build2
class variable_map
{
public:
+ struct value_data: value
+ {
+ using value::value;
+
+ size_t generation; // load_generation of this value (global only).
+ };
+
using map_type = butl::prefix_map<reference_wrapper<const variable>,
- value,
+ value_data,
'.'>;
using size_type = map_type::size_type;
template <typename I>
- struct iterator_adapter: I
+ class iterator_adapter: public I
{
+ public:
iterator_adapter () = default;
- iterator_adapter (const I& i): I (i) {}
+ iterator_adapter (const I& i, const variable_map& m): I (i), m_ (&m) {}
// Automatically type a newly typed value on access.
//
typename I::reference operator* () const;
- typename I::pointer operator-> () const;
+ typename I::pointer operator-> () const;
// Untyped access.
//
uint16_t extra () const {return I::operator* ().second.extra;}
typename I::reference untyped () const {return I::operator* ();}
+
+ private:
+ const variable_map* m_;
};
using const_iterator = iterator_adapter<map_type::const_iterator>;
@@ -1060,10 +1071,10 @@ namespace build2
// If typed is false, leave the value untyped even if the variable is.
//
- const value*
+ const value_data*
find (const variable&, bool typed = true) const;
- value*
+ value_data*
find (const variable&, bool typed = true);
// Return a value suitable for assignment. See scope for details.
@@ -1087,14 +1098,15 @@ namespace build2
find_namespace (const variable& ns) const
{
auto r (m_.find_prefix (ns));
- return make_pair (const_iterator (r.first), const_iterator (r.second));
+ return make_pair (const_iterator (r.first, *this),
+ const_iterator (r.second, *this));
}
const_iterator
- begin () const {return m_.begin ();}
+ begin () const {return const_iterator (m_.begin (), *this);}
const_iterator
- end () const {return m_.end ();}
+ end () const {return const_iterator (m_.end (), *this);}
bool
empty () const {return m_.empty ();}
@@ -1104,12 +1116,18 @@ namespace build2
public:
// Global should be true if this map is part of the global (model) state
- // (e.g., scope, target, etc).
+ // (e.g., scopes, etc).
//
explicit
variable_map (bool global = false): global_ (global) {}
private:
+ friend class variable_type_map;
+
+ void
+ typify (value_data&, const variable&) const;
+
+ private:
bool global_;
map_type m_;
};
diff --git a/build2/variable.cxx b/build2/variable.cxx
index 1cdde5e..963eb0e 100644
--- a/build2/variable.cxx
+++ b/build2/variable.cxx
@@ -1016,7 +1016,7 @@ namespace build2
t,
nullptr,
v != nullptr ? *v : variable_visibility::normal,
- load_generation}));
+ global_ ? load_generation : 0}));
variable& r (p.first->second);
@@ -1085,30 +1085,53 @@ namespace build2
// variable_map
//
- const value* variable_map::
- find (const variable& var, bool typed) const
+ void variable_map::
+ typify (value_data& v, const variable& var) const
+ {
+ // In the global state existing value can only be typified during
+ // the same load generation or during serial execution.
+ //
+ assert (!global_ ||
+ load_generation == 0 ||
+ v.generation == load_generation);
+
+ build2::typify (v, *var.type, &var);
+ }
+
+ auto variable_map::
+ find (const variable& var, bool typed) const -> const value_data*
{
auto i (m_.find (var));
- const value* r (i != m_.end () ? &i->second : nullptr);
+ const value_data* r (i != m_.end () ? &i->second : nullptr);
// First access after being assigned a type?
//
if (r != nullptr && typed && var.type != nullptr && r->type != var.type)
- typify (const_cast<value&> (*r), *var.type, &var);
+ {
+ // All values shall be typed during load.
+ //
+ assert (!global_ || phase == run_phase::load);
+ typify (const_cast<value_data&> (*r), var);
+ }
return r;
}
- value* variable_map::
- find (const variable& var, bool typed)
+ auto variable_map::
+ find (const variable& var, bool typed) -> value_data*
{
auto i (m_.find (var));
- value* r (i != m_.end () ? &i->second : nullptr);
+ value_data* r (i != m_.end () ? &i->second : nullptr);
// First access after being assigned a type?
//
if (r != nullptr && typed && var.type != nullptr && r->type != var.type)
- typify (*r, *var.type, &var);
+ {
+ // All values shall be typed during load.
+ //
+ assert (!global_ || phase == run_phase::load);
+ typify (*r, var);
+ }
return r;
}
@@ -1116,15 +1139,22 @@ namespace build2
pair<reference_wrapper<value>, bool> variable_map::
insert (const variable& var, bool typed)
{
- auto r (m_.emplace (var, value (typed ? var.type : nullptr)));
- value& v (r.first->second);
+ assert (!global_ || phase == run_phase::load);
- // First access after being assigned a type?
- //
- if (typed && !r.second && var.type != nullptr && v.type != var.type)
- typify (v, *var.type, &var);
+ auto p (m_.emplace (var, value_data (typed ? var.type : nullptr)));
+ value_data& r (p.first->second);
+
+ if (p.second)
+ r.generation = global_ ? load_generation : 0;
+ else
+ {
+ // First access after being assigned a type?
+ //
+ if (typed && var.type != nullptr && r.type != var.type)
+ typify (r, var);
+ }
- return make_pair (reference_wrapper<value> (v), r.second);
+ return make_pair (reference_wrapper<value> (r), p.second);
}
// variable_type_map
@@ -1187,12 +1217,19 @@ namespace build2
// to automatically type it. And if it is assignment, then typify it
// ourselves.
//
- if (const value* v = j->second.find (var, false))
+ const variable_map& vm (j->second);
+
+ if (const variable_map::value_data* v = vm.find (var, false))
{
if (v->extra == 0 && var.type != nullptr && v->type != var.type)
- typify (const_cast<value&> (*v), *var.type, &var);
-
- return lookup (v, &j->second);
+ {
+ // All values shall be typed during load.
+ //
+ assert (!global_ || phase == run_phase::load);
+ vm.typify (const_cast<variable_map::value_data&> (*v), var);
+ }
+
+ return lookup (v, &vm);
}
}
}
diff --git a/build2/variable.ixx b/build2/variable.ixx
index 816f4bf..8d5d710 100644
--- a/build2/variable.ixx
+++ b/build2/variable.ixx
@@ -639,18 +639,25 @@ namespace build2
// variable_map::iterator_adapter
//
+ extern run_phase phase; // context
+
template <typename I>
inline typename I::reference variable_map::iterator_adapter<I>::
operator* () const
{
auto& r (I::operator* ());
const variable& var (r.first);
- auto& val (r.second);
+ const value_data& val (r.second);
// First access after being assigned a type?
//
if (var.type != nullptr && val.type != var.type)
- typify (const_cast<value&> (val), *var.type, &var);
+ {
+ // All values shall be typed during load.
+ //
+ assert (!m_->global_ || phase == run_phase::load);
+ m_->typify (const_cast<value_data&> (val), var);
+ }
return r;
}
@@ -661,12 +668,17 @@ namespace build2
{
auto p (I::operator-> ());
const variable& var (p->first);
- auto& val (p->second);
+ const value_data& val (p->second);
// First access after being assigned a type?
//
if (var.type != nullptr && val.type != var.type)
- typify (const_cast<value&> (val), *var.type, &var);
+ {
+ // All values shall be typed during load.
+ //
+ assert (!m_->global_ || phase == run_phase::load);
+ m_->typify (const_cast<value_data&> (val), var);
+ }
return p;
}