From 977d07a3ae47ef204665d1eda2d642e5064724f3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 24 Jun 2019 12:01:19 +0200 Subject: Split build system into library and driver --- build2/function.cxx | 400 ---------------------------------------------------- 1 file changed, 400 deletions(-) delete mode 100644 build2/function.cxx (limited to 'build2/function.cxx') diff --git a/build2/function.cxx b/build2/function.cxx deleted file mode 100644 index e78cade..0000000 --- a/build2/function.cxx +++ /dev/null @@ -1,400 +0,0 @@ -// file : build2/function.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include // strchr() - -using namespace std; - -namespace build2 -{ - ostream& - operator<< (ostream& os, const function_overload& f) - { - os << f.name << '('; - - bool v (f.arg_max == function_overload::arg_variadic); - size_t n (v ? max (f.arg_min, f.arg_types.size ()): f.arg_max); - - // Handle variadic tail as the last pseudo-argument. - // - for (size_t i (0); i != n + (v ? 1 : 0); ++i) - { - if (i == f.arg_min) - os << (i != 0 ? " [" : "["); - - os << (i != 0 ? ", " : ""); - - if (i == n) // Variadic tail (last). - os << "..."; - else - { - // If count is greater than f.arg_typed, then we assume the rest are - // valid but untyped. - // - const optional t ( - i < f.arg_types.size () ? f.arg_types[i] : nullopt); - - os << (t ? (*t != nullptr ? (*t)->name : "") : ""); - } - } - - if (n + (v ? 1 : 0) > f.arg_min) - os << ']'; - - os << ')'; - - if (f.alt_name != nullptr) - { - auto k (strchr (f.alt_name, '.') == nullptr - ? "unqualified" - : "qualified"); - - os << ", " << k << " name " << f.alt_name; - } - - return os; - } - - bool function_map:: - defined (const string& name) const - { - assert (!name.empty ()); - - // If this is a qualified function name then check if it is already - // defined. - // - if (name.back () != '.') - return map_.find (name) != map_.end (); - - // If any function of the specified family is already defined, then one of - // them should be the first element that is greater than the dot-terminated - // family name. Here we rely on the fact that the dot character is less - // than any character of unqualified function and family names. - // - size_t n (name.size ()); - assert (n > 1); - - auto i (map_.upper_bound (name)); - return i != map_.end () && i->first.compare (0, n, name) == 0; - } - - auto function_map:: - insert (string name, function_overload f) -> iterator - { - // Sanity checks. - // - assert (f.arg_min <= f.arg_max && - f.arg_types.size () <= f.arg_max && - f.impl != nullptr); - - auto i (map_.emplace (move (name), move (f))); - - i->second.name = i->first.c_str (); - return i; - } - - pair function_map:: - call (const scope* base, - const string& name, - vector_view args, - const location& loc, - bool fa) const - { - auto print_call = [&name, &args] (ostream& os) - { - os << name << '('; - - for (size_t i (0); i != args.size (); ++i) - { - const value_type* t (args[i].type); - os << (i != 0 ? ", " : "") << (t != nullptr ? t->name : ""); - } - - os << ')'; - }; - - // Overload resolution. - // - // Ours is pretty simple: we sort all the overloads into three ranks: - // - // 0 -- all the arguments match exactly (perfect match) - // 1 -- one or more arguments match via the derived-to-base conversion - // 2 -- one or more arguments match via the reversal to untyped - // - // More than one match of the same rank is ambiguous. - // - auto ip (map_.equal_range (name)); - - size_t rank (~0); - small_vector ovls; - { - size_t count (args.size ()); - - for (auto it (ip.first); it != ip.second; ++it) - { - const function_overload& f (it->second); - - // Argument count match. - // - if (count < f.arg_min || count > f.arg_max) - continue; - - // Argument types match. - // - size_t r (0); - { - size_t i (0), n (min (count, f.arg_types.size ())); - for (; i != n; ++i) - { - if (!f.arg_types[i]) // Anytyped. - continue; - - const value_type* at (args[i].type); - const value_type* ft (*f.arg_types[i]); - - if (at == ft) // Types match perfectly. - continue; - - if (at != nullptr && ft != nullptr) - { - while ((at = at->base_type) != nullptr && at != ft) ; - - if (at != nullptr) // Types match via derived-to-base. - { - if (r < 1) - r = 1; - continue; - } - } - - if (ft == nullptr) // Types match via reversal to untyped. - { - if (r < 2) - r = 2; - continue; - } - - break; // No match. - } - - if (i != n) - continue; // No match. - } - - // Better or just as good a match? - // - if (r <= rank) - { - if (r < rank) // Better. - { - rank = r; - ovls.clear (); - } - - ovls.push_back (&f); - } - - // Continue looking to detect ambiguities. - } - } - - switch (ovls.size ()) - { - case 1: - { - // Print the call location in case the function fails. - // - auto g ( - make_exception_guard ( - [fa, &loc, &print_call] () - { - if (fa && verb != 0) - { - diag_record dr (info (loc)); - dr << "while calling "; print_call (dr.os); - } - })); - - auto f (ovls.back ()); - - // If one or more arguments match via the reversal to untyped (rank 2), - // then we need to go over the overload's arguments one more time an - // untypify() those that we need to reverse. - // - if (rank == 2) - { - size_t n (args.size ()); - assert (n <= f->arg_types.size ()); - - for (size_t i (0); i != n; ++i) - { - if (f->arg_types[i] && - *f->arg_types[i] == nullptr && - args[i].type != nullptr) - untypify (args[i]); - } - } - - try - { - return make_pair (f->impl (base, move (args), *f), true); - } - catch (const invalid_argument& e) - { - diag_record dr (fail); - dr << "invalid argument"; - - if (*e.what () != '\0') - dr << ": " << e; - - dr << endf; - } - } - case 0: - { - if (!fa) - return make_pair (value (nullptr), false); - - // No match. - // - diag_record dr; - - dr << fail (loc) << "unmatched call to "; print_call (dr.os); - - for (auto i (ip.first); i != ip.second; ++i) - dr << info << "candidate: " << i->second; - - // If this is an unqualified name, then also print qualified - // functions that end with this name. But skip functions that we - // have already printed in the previous loop. - // - if (name.find ('.') == string::npos) - { - size_t n (name.size ()); - - for (auto i (functions.begin ()); i != functions.end (); ++i) - { - const string& q (i->first); - const function_overload& f (i->second); - - if ((f.alt_name == nullptr || f.alt_name != name) && - q.size () > n) - { - size_t p (q.size () - n); - if (q[p - 1] == '.' && q.compare (p, n, name) == 0) - dr << info << "candidate: " << i->second; - } - } - } - - dr << endf; - } - default: - { - // Ambigous match. - // - diag_record dr; - dr << fail (loc) << "ambiguous call to "; print_call (dr.os); - - for (auto f: ovls) - dr << info << "candidate: " << *f; - - dr << endf; - } - } - } - - value function_family:: - default_thunk (const scope* base, - vector_view args, - const function_overload& f) - { - // Call the cast thunk. - // - struct cast_data // Prefix of function_cast::data. - { - value (*const thunk) (const scope*, vector_view, const void*); - }; - - auto d (reinterpret_cast (&f.data)); - return d->thunk (base, move (args), d); - } - -#if !defined(_MSC_VER) || _MSC_VER > 1910 - constexpr const optional* function_args<>::types; -#else - const optional* const function_args<>::types = nullptr; -#endif - - void function_family::entry:: - insert (string n, function_overload f) const - { - // Figure out qualification. - // - string qn; - size_t p (n.find ('.')); - - if (p == string::npos) - { - if (!qual.empty ()) - { - qn = qual; - qn += '.'; - qn += n; - } - } - else if (p == 0) - { - assert (!qual.empty ()); - n.insert (0, qual); - } - - auto i (qn.empty () ? functions.end () : functions.insert (move (qn), f)); - auto j (functions.insert (move (n), move (f))); - - // If we have both, then set alternative names. - // - if (i != functions.end ()) - { - i->second.alt_name = j->first.c_str (); - j->second.alt_name = i->first.c_str (); - } - } - - // Static-initialize the function map and populate with builtin functions. - // - function_map functions; - - void builtin_functions (); // functions-builtin.cxx - void filesystem_functions (); // functions-filesystem.cxx - void name_functions (); // functions-name.cxx - void path_functions (); // functions-path.cxx - void process_functions (); // functions-process.cxx - void process_path_functions (); // functions-process-path.cxx - void regex_functions (); // functions-regex.cxx - void string_functions (); // functions-string.cxx - void target_triplet_functions (); // functions-target-triplet.cxx - void project_name_functions (); // functions-target-triplet.cxx - - struct functions_init - { - functions_init () - { - builtin_functions (); - filesystem_functions (); - name_functions (); - path_functions (); - process_functions (); - process_path_functions (); - regex_functions (); - string_functions (); - target_triplet_functions (); - project_name_functions (); - } - }; - - static const functions_init init_; -} -- cgit v1.1