aboutsummaryrefslogtreecommitdiff
path: root/build
diff options
context:
space:
mode:
Diffstat (limited to 'build')
-rw-r--r--build/parser4
-rw-r--r--build/parser.cxx83
-rw-r--r--build/target.cxx56
3 files changed, 115 insertions, 28 deletions
diff --git a/build/parser b/build/parser
index 04066ff..e37e68a 100644
--- a/build/parser
+++ b/build/parser
@@ -25,6 +25,7 @@ namespace build
{
public:
typedef build::names names_type;
+ typedef build::variable variable_type;
parser (): fail (&path_) {}
@@ -77,6 +78,9 @@ namespace build
variable_name (names_type&&, const location&);
names_type
+ variable_value (token&, token_type&, const variable_type&);
+
+ names_type
eval (token&, token_type&);
// If chunk is true, then parse the smallest but complete, name-wise,
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)
{
diff --git a/build/target.cxx b/build/target.cxx
index 9b20273..22c9ad4 100644
--- a/build/target.cxx
+++ b/build/target.cxx
@@ -137,7 +137,7 @@ namespace build
{
if (!s->target_vars.empty ())
{
- auto find_specific = [&var, s] (const target& t) -> result
+ auto find_specific = [this, &var, s] (const target& t) -> result
{
// Search across target type hierarchy.
//
@@ -148,15 +148,51 @@ namespace build
if (i == s->target_vars.end ())
continue;
- //@@ TODO: match pattern. For now, we only handle '*'.
-
- auto j (i->second.find ("*"));
-
- if (j == i->second.end ())
- continue;
-
- if (auto p = j->second.find (var))
- return result (p, &j->second);
+ // Try to match the pattern, starting from the longest values
+ // so that the more "specific" patterns (i.e., those that cover
+ // fewer characters with the wildcard) take precedence. See
+ // tests/variable/type-pattern.
+ //
+ const variable_pattern_map& m (i->second);
+
+ for (auto j (m.rbegin ()); j != m.rend (); ++j)
+ {
+ const string& p (j->first);
+
+ size_t nn (name.size ());
+ size_t pn (p.size ());
+
+ if (nn < pn - 1) // One for '*'.
+ continue;
+
+ size_t w (p.find ('*'));
+ assert (w != string::npos);
+
+ // Compare prefix.
+ //
+ if (w != 0 &&
+ name.compare (0, w, p, 0, w) != 0)
+ continue;
+
+ ++w; // First suffix character.
+ pn -= w; // Suffix length.
+
+ // Compare suffix.
+ //
+ if (pn != 0 &&
+ name.compare (nn - pn, pn, p, w, pn) != 0)
+ continue;
+
+ // Ok, this pattern matches. But is there a variable?
+ //
+ if (const value* v = j->second.find (var))
+ {
+ //@@ TODO: should we detect ambiguity? 'foo-*' '*-foo' and
+ // 'foo-foo'? Right now the last defined will be used.
+ //
+ return result (v, &j->second);
+ }
+ }
}
return result ();