diff options
Diffstat (limited to 'build/variable.cxx')
-rw-r--r-- | build/variable.cxx | 452 |
1 files changed, 0 insertions, 452 deletions
diff --git a/build/variable.cxx b/build/variable.cxx deleted file mode 100644 index 6e02816..0000000 --- a/build/variable.cxx +++ /dev/null @@ -1,452 +0,0 @@ -// file : build/variable.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include <build/variable> - -#include <iterator> // make_move_iterator() - -#include <build/utility> -#include <build/diagnostics> - -using namespace std; - -namespace build -{ - // value - // - void - assign (value& v, const value_type* t, const variable& var) - { - if (v.type == nullptr) - { - v.type = t; - - if (v && t->assign != nullptr) - v.state_ = t->assign (v.data_, var) - ? value::state_type::filled - : value::state_type::empty; - } - else - fail << "variable '" << var.name << "' type mismatch" << - info << "value '" << v.data_ << "' is " << v.type->name << - info << (t == var.type ? "variable" : "new type") << " is " - << (var.type != nullptr ? var.type->name : "untyped"); - } - - value& value:: - operator= (value&& v) - { - assert (type == nullptr || type == v.type); - - // Since the types are the same, we don't need to call - // the callbacks. - // - type = v.type; - state_ = v.state_; - data_ = move (v.data_); - - return *this; - } - - value& value:: - append (value v, const variable& var) - { - assert (type == v.type); - append (move (v.data_), var); - return *this; - } - - value& value:: - prepend (value v, const variable& var) - { - assert (type == v.type); - prepend (move (v.data_), var); - return *this; - } - - void value:: - append (names v, const variable& var) - { - // Treat append to NULL as assign. - // - if (!null () && type != nullptr && type->append != nullptr) - { - state_ = type->append (data_, move (v), var) - ? state_type::filled - : state_type::empty; - return; - } - - if (data_.empty ()) - data_ = move (v); - else - data_.insert (data_.end (), - make_move_iterator (v.begin ()), - make_move_iterator (v.end ())); - - state_ = (type != nullptr && type->assign != nullptr - ? type->assign (data_, var) - : !data_.empty ()) - ? state_type::filled - : state_type::empty; - } - - void value:: - prepend (names v, const variable& var) - { - // Reduce to append. - // - if (!null () && type != nullptr && type->append != nullptr) - { - state_ = type->append (v, move (data_), var) - ? state_type::filled - : state_type::empty; - swap (data_, v); - return; - } - - if (data_.empty ()) - data_ = move (v); - else - { - v.insert (v.end (), - make_move_iterator (data_.begin ()), - make_move_iterator (data_.end ())); - swap (data_, v); - } - - state_ = (type != nullptr && type->assign != nullptr - ? type->assign (data_, var) - : !data_.empty ()) - ? state_type::filled - : state_type::empty; - } - - // bool value - // - bool value_traits<bool>:: - assign (name& n) - { - if (n.simple ()) - { - const string& s (n.value); - - if (s == "true" || s == "false") - return true; - } - - return false; - } - - static bool - bool_assign (names& v, const variable& var) - { - // Verify the value is either "true" or "false". - // - if (v.size () == 1) - { - name& n (v.front ()); - - if (value_traits<bool>::assign (n)) - return true; - } - - fail << "invalid bool variable '" << var.name << "' value '" << v << "'"; - return false; - } - - static bool - bool_append (names& v, names a, const variable& var) - { - // Translate append to OR. - // - bool_assign (a, var); // Verify "true" or "false". - - if (a.front ().value[0] == 't' && v.front ().value[0] == 'f') - v = move (a); - - return true; - } - - const value_type value_traits<bool>::value_type - { - "bool", - &bool_assign, - &bool_append - }; - - const value_type* bool_type = &value_traits<bool>::value_type; - - // string value - // - bool value_traits<string>:: - assign (name& n) - { - // The below code is quite convoluted because we don't want to - // modify the name until we know it good (if it is not, then it - // will most likely be printed by the caller in diagnostics). - - // Suspend project qualification. - // - const string* p (n.proj); - n.proj = nullptr; - - // Convert directory to string. - // - if (n.directory ()) - { - n.value = std::move (n.dir).string (); // Move string out of path. - - // Add / back to the end of the path unless it is already there. - // Note that the string cannot be empty (n.directory () would - // have been false). - // - if (!dir_path::traits::is_separator (n.value[n.value.size () - 1])) - n.value += '/'; - } - - if (!n.simple ()) - { - n.proj = p; // Restore. - return false; - } - - // Convert project qualification to its string representation. - // - if (p != nullptr) - { - string s (*p); - s += '%'; - s += n.value; - s.swap (n.value); - } - - return true; - } - - static bool - string_assign (names& v, const variable& var) - { - // Verify/convert the value is/to a single simple name. - // - if (v.empty ()) - { - v.emplace_back (name ()); // Canonical empty string representation. - return false; - } - else if (v.size () == 1) - { - name& n (v.front ()); - - if (value_traits<string>::assign (n)) - return !n.value.empty (); - } - - fail << "invalid string variable '" << var.name << "' value '" << v << "'"; - return false; - } - - static bool - string_append (names& v, names a, const variable& var) - { - // Translate append to string concatenation. - // - string_assign (a, var); // Verify/convert value is/to string. - - if (v.front ().value.empty ()) - v = move (a); - else - v.front ().value += a.front ().value; - - return !v.front ().value.empty (); - } - - const value_type value_traits<string>::value_type - { - "string", - &string_assign, - &string_append - }; - - const value_type* string_type = &value_traits<string>::value_type; - - // dir_path value - // - bool value_traits<dir_path>:: - assign (name& n) - { - if (n.directory ()) - return true; - - if (n.simple ()) - { - try - { - n.dir = n.empty () ? dir_path () : dir_path (move (n.value)); - n.value.clear (); - return true; - } - catch (const invalid_path&) {} // Fall through. - } - - return false; - } - - static bool - dir_path_assign (names& v, const variable& var) - { - // Verify/convert the value is/to a single directory name. - // - if (v.empty ()) - { - v.emplace_back (dir_path ()); // Canonical empty path representation. - return false; - } - else if (v.size () == 1) - { - name& n (v.front ()); - - if (value_traits<dir_path>::assign (n)) - return !n.dir.empty (); - } - - fail << "invalid dir_path variable '" << var.name << "' " - << "value '" << v << "'"; - return false; - } - - static bool - dir_path_append (names& v, names a, const variable& var) - { - // Translate append to path concatenation. - // - dir_path_assign (a, var); // Verify/convert value is/to dir_path. - - dir_path& d (a.front ().dir); - if (d.relative ()) - return !(v.front ().dir /= d).empty (); - else - fail << "append of absolute path '" << d << "' to dir_path variable " - << var.name; - - return false; - } - - const value_type value_traits<dir_path>::value_type - { - "dir_path", - &dir_path_assign, - &dir_path_append - }; - - const value_type* dir_path_type = &value_traits<dir_path>::value_type; - - // name value - // - static bool - name_assign (names& v, const variable& var) - { - // Verify the value is a single name. - // - if (v.size () == 1) - return v.front ().empty (); - - fail << "invalid string variable '" << var.name << "' value '" << v << "'"; - return false; - } - - static bool - name_append (names&, names, const variable& var) - { - fail << "append to name variable '" << var.name << "'"; - return false; - } - - const value_type value_traits<name>::value_type - { - "name", - &name_assign, - &name_append - }; - - const value_type* name_type = &value_traits<name>::value_type; - - // vector<T> value - // - const value_type* strings_type = &value_traits<strings>::value_type; - const value_type* dir_paths_type = &value_traits<dir_paths>::value_type; - const value_type* names_type = &value_traits<names>::value_type; - - // variable_set - // - variable_pool var_pool; - - // variable_type_map - // - lookup<const value> variable_type_map:: - lookup (const target_type& type, - const string& name, - const variable& var) const - { - using result = build::lookup<const value>; - - // Search across target type hierarchy. - // - for (auto tt (&type); tt != nullptr; tt = tt->base) - { - auto i (find (*tt)); - - if (i == end ()) - continue; - - // 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 (); - } -} |