aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/functions-name.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/functions-name.cxx')
-rw-r--r--libbuild2/functions-name.cxx226
1 files changed, 210 insertions, 16 deletions
diff --git a/libbuild2/functions-name.cxx b/libbuild2/functions-name.cxx
index 43bd8cb..84608d4 100644
--- a/libbuild2/functions-name.cxx
+++ b/libbuild2/functions-name.cxx
@@ -1,6 +1,8 @@
// file : libbuild2/functions-name.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
+#include <libbuild2/functions-name.hxx>
+
#include <libbuild2/scope.hxx>
#include <libbuild2/function.hxx>
#include <libbuild2/variable.hxx>
@@ -10,35 +12,37 @@ using namespace std;
namespace build2
{
+ extern bool
+ functions_sort_flags (optional<names>); // functions-builtin.cxx
+
// Convert name to target'ish name (see below for the 'ish part). Return
// raw/unprocessed data in case this is an unknown target type (or called
// out of scope). See scope::find_target_type() for details. Allow out-
// qualified names (out is discarded).
//
- static pair<name, optional<string>>
- to_target_name (const scope* s, name&& n, const name& o = name ())
+ static pair<const target_type*, optional<string>>
+ to_target_type (const scope* s, name& n, const name& o = name ())
{
if (n.pair && !o.directory ())
fail << "name pair in names";
- optional<string> e;
-
- if (s != nullptr)
- {
- auto rp (s->find_target_type (n, location ()));
+ return s != nullptr
+ ? s->find_target_type (n, location ())
+ : pair<const target_type*, optional<string>> {nullptr, nullopt};
+ }
- if (rp.first != nullptr)
- n.type = rp.first->name;
+ static pair<name, optional<string>>
+ to_target_name (const scope* s, name&& n, const name& o = name ())
+ {
+ auto rp (to_target_type (s, n, o));
- e = move (rp.second);
- }
+ if (rp.first != nullptr)
+ n.type = rp.first->name;
- return make_pair (move (n), move (e));
+ return make_pair (move (n), move (rp.second));
}
- // Note: this helper mey be used by other functions that operate on targets.
- //
- LIBBUILD2_SYMEXPORT const target&
+ const target&
to_target (const scope& s, name&& n, name&& o)
{
if (const target* r = search_existing (n, s, o.dir))
@@ -49,6 +53,81 @@ namespace build2
<< " not found" << endf;
}
+ const target&
+ to_target (const scope& s, names&& ns)
+ {
+ assert (ns.size () == (ns[0].pair ? 2 : 1));
+
+ name o;
+ return to_target (s, move (ns[0]), move (ns[0].pair ? ns[1] : o));
+ }
+
+ static bool
+ is_a (const scope* s, name&& n, const name& o, names&& t)
+ {
+ if (s == nullptr)
+ fail << "name.is_a() called out of scope";
+
+ string tts (convert<string> (move (t)));
+ const target_type* tt (s->find_target_type (tts));
+ if (tt == nullptr)
+ fail << "unknown target type " << tts;
+
+ const target_type* ntt (to_target_type (s, n, o).first);
+ if (ntt == nullptr)
+ fail << "unknown target type " << n.type << " in " << n;
+
+ return ntt->is_a (*tt);
+ }
+
+ static names
+ filter (const scope* s, names ns, names ts, bool out)
+ {
+ if (s == nullptr)
+ fail << "name." << (out ? "filter_out" : "filter")
+ << "() called out of scope";
+
+ small_vector<const target_type*, 1> tts;
+ for (const name& n: ts)
+ {
+ if (!n.simple ())
+ fail << "invalid target type name " << n;
+
+ if (n.pair)
+ fail << "pair in target type name " << n;
+
+ const target_type* tt (s->find_target_type (n.value));
+ if (tt == nullptr)
+ fail << "unknown target type " << n.value;
+
+ tts.push_back (tt);
+ }
+
+ names r;
+ for (auto i (ns.begin ()); i != ns.end (); ++i)
+ {
+ name& n (*i);
+ bool p (n.pair);
+
+ const target_type* ntt (to_target_type (s, n, p ? *++i : name ()).first);
+ if (ntt == nullptr)
+ fail << "unknown target type " << n.type << " in " << n;
+
+ if ((find_if (tts.begin (), tts.end (),
+ [ntt] (const target_type* tt)
+ {
+ return ntt->is_a (*tt);
+ }) != tts.end ()) != out)
+ {
+ r.push_back (move (n));
+ if (p)
+ r.push_back (move (*i));
+ }
+ }
+
+ return r;
+ }
+
void
name_functions (function_map& m)
{
@@ -63,6 +142,14 @@ namespace build2
//
function_family fn (m, "name");
+ // Note that we must handle NULL values (relied upon by the parser
+ // to provide conversion semantics consistent with untyped values).
+ //
+ fn["string"] += [](name* n)
+ {
+ return n != nullptr ? to_string (move (*n)) : string ();
+ };
+
fn["name"] += [](const scope* s, name n)
{
return to_target_name (s, move (n)).first.value;
@@ -172,6 +259,108 @@ namespace build2
return to_target_name (s, move (n), o).first.proj;
};
+ // $is_a(<name>, <target-type>)
+ //
+ // Return true if the <name>'s target type is-a <target-type>. Note that
+ // this is a dynamic type check that takes into account target type
+ // inheritance.
+ //
+ fn["is_a"] += [](const scope* s, name n, names t)
+ {
+ return is_a (s, move (n), name (), move (t));
+ };
+ fn["is_a"] += [](const scope* s, names ns, names t)
+ {
+ auto i (ns.begin ());
+
+ name& n (*i);
+ const name& o (n.pair ? *++i : name ());
+
+ if (++i != ns.end ())
+ fail << "invalid name value: multiple names"; // Like in convert().
+
+ return is_a (s, move (n), o, move (t));
+ };
+
+ // $filter(<names>, <target-types>)
+ // $filter_out(<names>, <target-types>)
+ //
+ // Return names with target types which are-a (filter) or not are-a
+ // (filter_out) one of <target-types>. See $is_a() for background.
+ //
+ fn["filter"] += [](const scope* s, names ns, names ts)
+ {
+ return filter (s, move (ns), move (ts), false /* out */);
+ };
+
+ fn["filter_out"] += [](const scope* s, names ns, names ts)
+ {
+ return filter (s, move (ns), move (ts), true /* out */);
+ };
+
+ // $size(<names>)
+ //
+ // Return the number of elements in the sequence.
+ //
+ fn["size"] += [] (names ns)
+ {
+ size_t n (0);
+
+ for (auto i (ns.begin ()); i != ns.end (); ++i)
+ {
+ ++n;
+ if (i->pair && !(++i)->directory ())
+ fail << "name pair in names";
+ }
+
+ return n;
+ };
+
+ // $sort(<names> [, <flags>])
+ //
+ // Sort names in ascending order.
+ //
+ // The following flags are supported:
+ //
+ // dedup - in addition to sorting also remove duplicates
+ //
+ fn["sort"] += [] (names ns, optional<names> fs)
+ {
+ //@@ TODO: shouldn't we do this in a pair-aware manner?
+
+ sort (ns.begin (), ns.end ());
+
+ if (functions_sort_flags (move (fs)))
+ ns.erase (unique (ns.begin(), ns.end()), ns.end ());
+
+ return ns;
+ };
+
+ // $find(<names>, <name>)
+ //
+ // Return true if the name sequence contains the specified name.
+ //
+ fn["find"] += [](names vs, names v)
+ {
+ //@@ TODO: shouldn't we do this in a pair-aware manner?
+
+ return find (vs.begin (), vs.end (),
+ convert<name> (move (v))) != vs.end ();
+ };
+
+ // $find_index(<names>, <name>)
+ //
+ // Return the index of the first element in the name sequence that is
+ // equal to the specified name or $size(<names>) if none is found.
+ //
+ fn["find_index"] += [](names vs, names v)
+ {
+ //@@ TODO: shouldn't we do this in a pair-aware manner?
+
+ auto i (find (vs.begin (), vs.end (), convert<name> (move (v))));
+ return i != vs.end () ? i - vs.begin () : vs.size ();
+ };
+
// Functions that can be called only on real targets.
//
function_family ft (m, "target");
@@ -226,7 +415,7 @@ namespace build2
// Note that while this function is not technically pure, we don't mark it
// as such for the same reasons as $path() above.
//
- fn["process_path"] += [](const scope* s, names ns)
+ ft["process_path"] += [](const scope* s, names ns)
{
if (s == nullptr)
fail << "target.process_path() called out of scope";
@@ -255,6 +444,11 @@ namespace build2
//
function_family fb (m, "builtin");
+ // Note that while we should normally handle NULL values (relied upon by
+ // the parser to provide concatenation semantics consistent with untyped
+ // values), the result will unlikely be what the user expected. So for now
+ // we keep it a bit tighter.
+ //
fb[".concat"] += [](dir_path d, name n)
{
d /= n.dir;