From 6b7075adc71104c5f6ad652b99fb753565eb67d8 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 18 Nov 2016 17:28:46 +0200 Subject: Add function machinery, implement path.normalize() Note that multi-argument functions are not yet "callable" since there is no support for value packs. --- build2/function.cxx | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 build2/function.cxx (limited to 'build2/function.cxx') diff --git a/build2/function.cxx b/build2/function.cxx new file mode 100644 index 0000000..91c5b3e --- /dev/null +++ b/build2/function.cxx @@ -0,0 +1,231 @@ +// file : build2/function.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +using namespace std; + +namespace build2 +{ + 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; + } + + value function_map:: + call (const string& name, vector_view args, const location& loc) + { + 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 << ')'; + }; + + auto print_fovl = [&name] (ostream& os, const function_overload& f) + { + os << 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.qual_name) + os << ", qualified name " << f.qual_name; + }; + + // Overload resolution. + // + const function_overload* r (nullptr); + + size_t count (args.size ()); + auto ip (map_.equal_range (name)); + + 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 i (0), n (min (count, f.arg_types.size ())); + for (; i != n; ++i) + if (f.arg_types[i] && *f.arg_types[i] != args[i].type) + break; + + if (i != n) + continue; + } + + if (r != nullptr) + { + diag_record dr (fail (loc)); + + dr << "ambiguous call to "; print_call (dr.os); + dr << info << " candidate: "; print_fovl (dr.os, *r); + dr << info << " candidate: "; print_fovl (dr.os, f); + } + + r = &f; // Continue looking to detect ambiguities. + } + + if (r == nullptr) + { + diag_record dr (fail (loc)); + + dr << "unmatched call to "; print_call (dr.os); + + for (auto it (ip.first); it != ip.second; ++it) + { + const function_overload& f (it->second); + + dr << info << " candidate: "; print_fovl (dr.os, f); + } + } + + // Print the call location if the function fails. + // + auto g ( + make_exception_guard ( + [&loc, &print_call] () + { + if (verb != 0) + { + diag_record dr (info (loc)); + dr << "while calling "; print_call (dr.os); + } + })); + + return r->impl (move (args), *r); + } + + value function_family:: + default_thunk (vector_view args, const function_overload& f) + try + { + // Call the cast thunk. + // + struct cast_data // Prefix of function_cast::data. + { + value (*const thunk) (vector_view, const void*); + }; + + auto d (reinterpret_cast (&f.data)); + return d->thunk (move (args), d); + } + catch (const invalid_argument& e) + { + { + diag_record dr (error); + dr << "invalid argument"; + + const char* w (e.what ()); + if (*w != '\0') + dr << ": " << w; + } + + throw failed (); + } + + const optional* const function_args<>::types = nullptr; + + 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); + } + + // First insert the qualified name and use its key for f.qual_name. + // + if (!qn.empty ()) + { + auto i (functions.insert (move (qn), f)); + f.qual_name = i->first.c_str (); + } + + functions.insert (move (n), move (f)); + } + + // Static-initialize the function map and populate with builtin functions. + // + function_map functions; + + void + path_functions (); // functions-path.cxx + + struct functions_init + { + functions_init () + { + path_functions (); + } + }; + + static const functions_init init_; +} -- cgit v1.1