aboutsummaryrefslogtreecommitdiff
path: root/build2/variable.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-11-23 16:53:31 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-11-23 16:53:31 +0200
commite19095ef128f53644bc7650094d8924633c79efa (patch)
treed039eb841341af2d7b3f544b95644ad1afcb846c /build2/variable.cxx
parent793f078ec31dc61921b382f14412ed3e25cc51d8 (diff)
Implement value type propagation on expansion
Currently, we only propagate types of sole, unquoted expansions (variable, function call, or eval context), similar to NULL. To untypify the value, simply quote it.
Diffstat (limited to 'build2/variable.cxx')
-rw-r--r--build2/variable.cxx73
1 files changed, 68 insertions, 5 deletions
diff --git a/build2/variable.cxx b/build2/variable.cxx
index 39fdb5d..5a52557 100644
--- a/build2/variable.cxx
+++ b/build2/variable.cxx
@@ -336,6 +336,41 @@ namespace build2
}
}
+ void
+ untypify (value& v)
+ {
+ if (v.type == nullptr)
+ return;
+
+ if (v.null)
+ {
+ v.type = nullptr;
+ return;
+ }
+
+ names ns;
+ names_view nv (v.type->reverse (v, ns));
+
+ if (nv.empty () || nv.data () == ns.data ())
+ {
+ // If the data is in storage, then we are all set.
+ //
+ ns.resize (nv.size ()); // Just to be sure.
+ }
+ else
+ {
+ // If the data is somewhere in the value itself, then steal it.
+ //
+ auto b (const_cast<name*> (nv.data ()));
+ ns.assign (make_move_iterator (b),
+ make_move_iterator (b + nv.size ()));
+ }
+
+ v = nullptr; // Free old data.
+ v.type = nullptr; // Change type.
+ v.assign (move (ns), nullptr); // Assign new data.
+ }
+
// Throw invalid_argument for an invalid simple value.
//
[[noreturn]] static void
@@ -736,6 +771,34 @@ namespace build2
}
void
+ process_path_assign (value& v, names&& ns, const variable* var)
+ {
+ using traits = value_traits<process_path>;
+
+ size_t n (ns.size ());
+
+ if (n <= 2)
+ {
+ try
+ {
+ traits::assign (
+ v,
+ (n == 0
+ ? process_path ()
+ : traits::convert (move (ns[0]), n == 2 ? &ns[1] : nullptr)));
+ return;
+ }
+ catch (const invalid_argument&) {} // Fall through.
+ }
+
+ diag_record dr (fail);
+ dr << "invalid process_path value '" << ns << "'";
+
+ if (var != nullptr)
+ dr << " in variable " << var->name;
+ }
+
+ void
process_path_copy_ctor (value& l, const value& r, bool m)
{
const auto& rhs (r.as<process_path> ());
@@ -798,15 +861,15 @@ namespace build2
{
type_name,
sizeof (process_path),
- nullptr, // No base.
+ nullptr, // No base.
&default_dtor<process_path>,
&process_path_copy_ctor,
&process_path_copy_assign,
- &simple_assign<process_path, true>, // Allow empty values.
- nullptr, // Append not supported.
- nullptr, // Prepend not supported.
+ &process_path_assign,
+ nullptr, // Append not supported.
+ nullptr, // Prepend not supported.
&process_path_reverse,
- nullptr, // No cast (cast data_ directly).
+ nullptr, // No cast (cast data_ directly).
&simple_compare<process_path>,
&default_empty<process_path>
};