aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-06-28 11:04:24 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-06-28 11:04:24 +0200
commit9ca783f9fab41eac40b96313749533ea5c965426 (patch)
treecf1ee86bc0153fb972e99dc882b4d1823805725b
parent3cc5e3bd441fc9d18fece3d9e99fae75c78438e7 (diff)
Add prerequisite variable visibility specification/enforcement
-rw-r--r--build2/context.cxx5
-rw-r--r--build2/parser.cxx46
-rw-r--r--build2/prerequisite.hxx2
-rw-r--r--build2/scope.cxx6
-rw-r--r--build2/test/init.cxx8
-rw-r--r--build2/variable.cxx19
-rw-r--r--build2/variable.hxx41
7 files changed, 106 insertions, 21 deletions
diff --git a/build2/context.cxx b/build2/context.cxx
index 4884145..5a94772 100644
--- a/build2/context.cxx
+++ b/build2/context.cxx
@@ -693,6 +693,7 @@ namespace build2
{
auto v_p (variable_visibility::project);
auto v_t (variable_visibility::target);
+ auto v_q (variable_visibility::prereq);
var_src_root = &vp.insert<dir_path> ("src_root");
var_out_root = &vp.insert<dir_path> ("out_root");
@@ -714,9 +715,9 @@ namespace build2
var_import_target = &vp.insert<name> ("import.target");
- var_clean = &vp.insert<bool> ("clean", v_t);
+ var_clean = &vp.insert<bool> ("clean", v_t);
var_backlink = &vp.insert<string> ("backlink", v_t);
- var_include = &vp.insert<string> ("include", v_t);
+ var_include = &vp.insert<string> ("include", v_q);
vp.insert<string> (var_extension, v_t);
diff --git a/build2/parser.cxx b/build2/parser.cxx
index dfa9916..4fe30e9 100644
--- a/build2/parser.cxx
+++ b/build2/parser.cxx
@@ -544,6 +544,12 @@ namespace build2
const variable& var (parse_variable_name (move (pns), ploc));
apply_variable_attributes (var);
+ if (var.visibility >= variable_visibility::prereq)
+ {
+ fail (nloc) << "variable " << var << " has " << var.visibility
+ << " visibility but is assigned in a target";
+ }
+
// If we have multiple targets, then we save the value tokens when
// parsing the first one and then replay them for the subsequent.
// We have to do it this way because the value may contain
@@ -898,10 +904,16 @@ namespace build2
const variable& var (parse_variable_name (move (ns), nloc));
apply_variable_attributes (var);
- if (var.visibility == variable_visibility::target)
- fail (nloc) << "variable " << var << " has target visibility but "
- << "assigned in a scope" <<
- info << "consider changing to '*: " << var << "'";
+ if (var.visibility >= variable_visibility::target)
+ {
+ diag_record dr (fail (nloc));
+
+ dr << "variable " << var << " has " << var.visibility
+ << " visibility but is assigned in a scope";
+
+ if (var.visibility == variable_visibility::target)
+ dr << info << "consider changing it to '*: " << var << "'";
+ }
{
enter_scope sg (d.empty ()
@@ -1325,6 +1337,8 @@ namespace build2
//
auto at (attributes_push (t, tt));
+ const location vloc (get_location (t));
+
if (tt == type::word)
{
// Split the token into the variable name and value at position (p) of
@@ -1395,6 +1409,12 @@ namespace build2
{
apply_variable_attributes (*var);
+ if (var->visibility >= variable_visibility::target)
+ {
+ fail (vloc) << "variable " << *var << " has " << var->visibility
+ << " visibility but is assigned in import";
+ }
+
val = atype == type::assign
? &scope_->assign (*var)
: &scope_->append (*var);
@@ -1770,9 +1790,11 @@ namespace build2
const variable& var (parse_variable_name (move (vns), vloc));
apply_variable_attributes (var);
- if (var.visibility == variable_visibility::target)
- fail (vloc) << "variable " << var << " has target visibility but "
- << "assigned in for-loop";
+ if (var.visibility >= variable_visibility::target)
+ {
+ fail (vloc) << "variable " << var << " has " << var.visibility
+ << " visibility but is assigned in for-loop";
+ }
// Now the value (list of names) to iterate over. Parse it as a variable
// value to get expansion, attributes, etc.
@@ -4701,9 +4723,13 @@ namespace build2
//
const auto& var (var_pool.rw (*scope_).insert (move (name), true));
- if (target_ == nullptr && var.visibility == variable_visibility::target)
- fail (loc) << "variable " << var << " has target visibility but "
- << "expanded in a scope";
+ if ((var.visibility == variable_visibility::prereq) ||
+ (var.visibility == variable_visibility::target && target_ == nullptr))
+ {
+ fail (loc) << "variable " << var << " has " << var.visibility
+ << " visibility but is expanded in a "
+ << (target_ != nullptr ? "target" : "scope");
+ }
return target_ != nullptr ? (*target_)[var] : (*scope_)[var];
diff --git a/build2/prerequisite.hxx b/build2/prerequisite.hxx
index 6ae6ec7..b8707ce 100644
--- a/build2/prerequisite.hxx
+++ b/build2/prerequisite.hxx
@@ -84,6 +84,8 @@ namespace build2
// Prerequisite-specific variables.
//
+ // Note that the lookup is often ad hoc (see bin.whole as an example).
+ //
public:
variable_map vars;
diff --git a/build2/scope.cxx b/build2/scope.cxx
index ff004b5..dc08925 100644
--- a/build2/scope.cxx
+++ b/build2/scope.cxx
@@ -23,6 +23,9 @@ namespace build2
size_t d (0);
+ if (var.visibility == variable_visibility::prereq)
+ return make_pair (lookup (), d);
+
// Process target type/pattern-specific prepend/append values.
//
auto pre_app = [&var] (lookup& l,
@@ -164,6 +167,8 @@ namespace build2
case variable_visibility::normal:
s = s->parent_scope ();
break;
+ case variable_visibility::prereq:
+ assert (false);
}
}
@@ -247,6 +252,7 @@ namespace build2
case variable_visibility::normal:
break;
case variable_visibility::target:
+ case variable_visibility::prereq:
assert (false);
}
diff --git a/build2/test/init.cxx b/build2/test/init.cxx
index 66889f7..822a444 100644
--- a/build2/test/init.cxx
+++ b/build2/test/init.cxx
@@ -85,10 +85,10 @@ namespace build2
// appending the input paths to test.arguments or by passing them in a
// separate test.inputs variable).
//
- vp.insert<bool> ("test.stdin", variable_visibility::target),
- vp.insert<bool> ("test.stdout", variable_visibility::target),
- vp.insert<bool> ("test.roundtrip", variable_visibility::target),
- vp.insert<bool> ("test.input", variable_visibility::target),
+ vp.insert<bool> ("test.stdin", variable_visibility::prereq),
+ vp.insert<bool> ("test.stdout", variable_visibility::prereq),
+ vp.insert<bool> ("test.roundtrip", variable_visibility::prereq),
+ vp.insert<bool> ("test.input", variable_visibility::prereq),
// Test target platform.
//
diff --git a/build2/variable.cxx b/build2/variable.cxx
index 0c07db6..406123d 100644
--- a/build2/variable.cxx
+++ b/build2/variable.cxx
@@ -13,6 +13,25 @@ using namespace std;
namespace build2
{
+ // variable_visibility
+ //
+ ostream&
+ operator<< (ostream& o, variable_visibility v)
+ {
+ const char* s (nullptr);
+
+ switch (v)
+ {
+ case variable_visibility::normal: s = "normal"; break;
+ case variable_visibility::project: s = "project"; break;
+ case variable_visibility::scope: s = "scope"; break;
+ case variable_visibility::target: s = "target"; break;
+ case variable_visibility::prereq: s = "prerequisite"; break;
+ }
+
+ return o << s;
+ }
+
// value
//
void value::
diff --git a/build2/variable.hxx b/build2/variable.hxx
index 4d11b25..e11d00c 100644
--- a/build2/variable.hxx
+++ b/build2/variable.hxx
@@ -94,17 +94,48 @@ namespace build2
bool (*const empty) (const value&);
};
- enum class variable_visibility
+ // The order of the enumerators is arranged so that their integral values
+ // indicate whether one is more restrictive than the other.
+ //
+ enum class variable_visibility: uint8_t
{
// Note that the search for target type/pattern-specific terminates at
// the project boundary.
//
- target, // Target and target type/pattern-specific.
- scope, // This scope (no outer scopes).
- project, // This project (no outer projects).
- normal // All outer scopes.
+ normal, // All outer scopes.
+ project, // This project (no outer projects).
+ scope, // This scope (no outer scopes).
+ target, // Target and target type/pattern-specific.
+ prereq // Prerequisite-specific.
};
+ inline bool
+ operator> (variable_visibility l, variable_visibility r)
+ {
+ return static_cast<uint8_t> (l) > static_cast<uint8_t> (r);
+ }
+
+ inline bool
+ operator>= (variable_visibility l, variable_visibility r)
+ {
+ return static_cast<uint8_t> (l) >= static_cast<uint8_t> (r);
+ }
+
+ inline bool
+ operator< (variable_visibility l, variable_visibility r)
+ {
+ return r > l;
+ }
+
+ inline bool
+ operator<= (variable_visibility l, variable_visibility r)
+ {
+ return r >= l;
+ }
+
+ ostream&
+ operator<< (ostream&, variable_visibility);
+
// variable
//
// The two variables are considered the same if they have the same name.