aboutsummaryrefslogtreecommitdiff
path: root/build/parser.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-11-30 14:31:40 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-11-30 14:36:18 +0200
commitb2374e3174e13682fcfa3ffe3fc62f2fd161a7cc (patch)
treebd39bda41e2ee352b73d80b84153ba95b80e84c4 /build/parser.cxx
parent1fb88fce9681e88f4140457cfe00a998d9c2588d (diff)
Implement target type/pattern-specific variables
For example: cxx{*-options}: dist = true 1. Only single '*' wildcard is supported, matches 0 or more characters. 2. If target type is not specified, it defaults to any target. 3. Appending (+=) is not allowed. 4. The value is expanded immediately in the context of the scope. 5. The more specific pattern (i.e., with the shortest "stem") is preferred. If the stem has the same length, then the last defined (but not redefined) pattern is used. This will probably have to change to become an error. See tests/variable/type-pattern for more examples.
Diffstat (limited to 'build/parser.cxx')
-rw-r--r--build/parser.cxx83
1 files changed, 65 insertions, 18 deletions
diff --git a/build/parser.cxx b/build/parser.cxx
index 4ce9fba..bc6caa9 100644
--- a/build/parser.cxx
+++ b/build/parser.cxx
@@ -279,7 +279,7 @@ namespace build
//
if (tt == type::equal || tt == type::plus_equal)
{
- string var (variable_name (move (pns), ploc));
+ string v (variable_name (move (pns), ploc));
// Enter the target/scope and set it as current.
//
@@ -307,19 +307,61 @@ namespace build
scope* ocs (scope_);
switch_scope (p);
- variable (t, tt, move (var), tt);
+ variable (t, tt, move (v), tt);
scope_ = ocs;
root_ = ors;
}
else
{
- target* ot (target_);
- target_ = &enter_target (move (n));
-
- variable (t, tt, move (var), tt);
+ // Figure out if this is a target or type/pattern specific
+ // variable.
+ //
+ size_t p (n.value.find ('*'));
- target_ = ot;
+ if (p == string::npos)
+ {
+ target* ot (target_);
+ target_ = &enter_target (move (n));
+ variable (t, tt, move (v), tt);
+ target_ = ot;
+ }
+ else
+ {
+ // See tests/variable/type-pattern.
+ //
+ if (!n.dir.empty ())
+ fail (nloc) << "directory in target type/pattern " << n;
+
+ if (n.value.find ('*', p + 1) != string::npos)
+ fail (nloc) << "multiple wildcards in target type/pattern "
+ << n;
+
+ // Resolve target type. If none is specified, use the root
+ // of the hierarchy.
+ //
+ const target_type* ti (
+ n.untyped ()
+ ? &target::static_type
+ : scope_->find_target_type (n.type.c_str ()));
+
+ if (ti == nullptr)
+ fail (nloc) << "unknown target type " << n.type;
+
+ if (tt == type::plus_equal)
+ fail (t) << "append to target type/pattern-specific "
+ << "variable " << v;
+
+ const auto& var (variable_pool.find (move (v)));
+
+ // Note: expand variables in the value in the context of
+ // the scope.
+ //
+ names_type vns (variable_value (t, tt, var));
+ value& val (
+ scope_->target_vars[*ti][move (n.value)].assign (var).first);
+ val.assign (move (vns), var);
+ }
}
}
// Dependency declaration.
@@ -797,19 +839,10 @@ namespace build
void parser::
variable (token& t, token_type& tt, string name, token_type kind)
{
- bool assign (kind == type::equal);
const auto& var (variable_pool.find (move (name)));
+ names_type vns (variable_value (t, tt, var));
- if (var.pairs != '\0')
- lexer_->mode (lexer_mode::pairs, var.pairs);
- else
- lexer_->mode (lexer_mode::value);
-
- next (t, tt);
- names_type vns (tt != type::newline && tt != type::eos
- ? names (t, tt)
- : names_type ());
- if (assign)
+ if (kind == type::equal)
{
value& v (target_ != nullptr
? target_->assign (var)
@@ -825,6 +858,20 @@ namespace build
}
}
+ names parser::
+ variable_value (token& t, token_type& tt, const variable_type& var)
+ {
+ if (var.pairs != '\0')
+ lexer_->mode (lexer_mode::pairs, var.pairs);
+ else
+ lexer_->mode (lexer_mode::value);
+
+ next (t, tt);
+ return (tt != type::newline && tt != type::eos
+ ? names (t, tt)
+ : names_type ());
+ }
+
parser::names_type parser::
eval (token& t, token_type& tt)
{