aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-03-17 07:33:41 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-03-17 07:47:17 +0200
commitbab021a6203127f38fb89c61cc41deb3e0abbe62 (patch)
tree868ddce415b985636baed5dd566ec4bd11f67c99
parent962f83b1e551cc683f1052d32cb79b969e65af5f (diff)
Add $defined(<variable>) function
-rw-r--r--libbuild2/function.cxx9
-rw-r--r--libbuild2/function.hxx11
-rw-r--r--libbuild2/functions-builtin.cxx46
-rw-r--r--tests/function/builtin/testscript19
4 files changed, 52 insertions, 33 deletions
diff --git a/libbuild2/function.cxx b/libbuild2/function.cxx
index 79e7a81..25dacf9 100644
--- a/libbuild2/function.cxx
+++ b/libbuild2/function.cxx
@@ -117,13 +117,8 @@ namespace build2
// 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.
+ // See the overall function machinery description for the ranking
+ // semantics.
//
auto ip (map_.equal_range (name));
diff --git a/libbuild2/function.hxx b/libbuild2/function.hxx
index ce47bd9..b745173 100644
--- a/libbuild2/function.hxx
+++ b/libbuild2/function.hxx
@@ -32,7 +32,7 @@ namespace build2
// as arguments. There is also higher-level, more convenient support for
// defining functions as pointers to functions (including capture-less
// lambdas), pointers to member functions (e.g., string::size()), or
- // pointers to data members (e.g., name::type). In this case the build2
+ // pointers to data members (e.g., name::type). In this case the buildfile
// function types are automatically matched to C++ function types according
// to these rules:
//
@@ -43,6 +43,15 @@ namespace build2
// value* - NULL-able any type (never NULL itself, use value::null)
// optional<T> - optional argument (here T can be T*, names, value)
//
+ // The overload resolution is pretty simple: we sort all the candidates 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.
+ //
// Optional arguments must be last. In case of a failure the function is
// expected to issue diagnostics and throw failed. Note that the arguments
// are conceptually "moved" and can be reused by the implementation.
diff --git a/libbuild2/functions-builtin.cxx b/libbuild2/functions-builtin.cxx
index 4c5929b..c4f0314 100644
--- a/libbuild2/functions-builtin.cxx
+++ b/libbuild2/functions-builtin.cxx
@@ -3,6 +3,7 @@
#include <sstream>
+#include <libbuild2/scope.hxx>
#include <libbuild2/function.hxx>
#include <libbuild2/variable.hxx>
@@ -10,29 +11,23 @@ using namespace std;
namespace build2
{
- // Return NULL value if an environment variable is not set, untyped value
- // otherwise.
- //
- static inline value
- getenvvar (const string& name)
- {
- optional<string> v (getenv (name));
-
- if (!v)
- return value ();
-
- names r;
- r.emplace_back (to_name (move (*v)));
- return value (move (r));
- }
-
void
builtin_functions (function_map& m)
{
function_family f (m, "builtin");
- f["type"] = [](value* v) {return v->type != nullptr ? v->type->name : "";};
+ // Note that we may want to extend the scope argument to a more general
+ // notion of "lookup context" (scope, target, prerequisite).
+ //
+ f["defined"] = [](const scope* s, names name)
+ {
+ if (s == nullptr)
+ fail << "defined() called out of scope" << endf;
+ return (*s)[convert<string> (move (name))].defined ();
+ };
+
+ f["type"] = [](value* v) {return v->type != nullptr ? v->type->name : "";};
f["null"] = [](value* v) {return v->null;};
f["empty"] = [](value* v) {return v->null || v->empty ();};
@@ -67,14 +62,19 @@ namespace build2
// getenv
//
- f["getenv"] = [](string name)
- {
- return getenvvar (name);
- };
-
+ // Return NULL if the environment variable is not set, untyped value
+ // otherwise.
+ //
f["getenv"] = [](names name)
{
- return getenvvar (convert<string> (move (name)));
+ optional<string> v (getenv (convert<string> (move (name))));
+
+ if (!v)
+ return value ();
+
+ names r;
+ r.emplace_back (to_name (move (*v)));
+ return value (move (r));
};
}
}
diff --git a/tests/function/builtin/testscript b/tests/function/builtin/testscript
index acd544d..3d31ca2 100644
--- a/tests/function/builtin/testscript
+++ b/tests/function/builtin/testscript
@@ -3,6 +3,23 @@
.include ../../common.testscript
+: defined
+:
+{
+ : true
+ :
+ $* <<EOI >'true'
+ foo = [null]
+ print $defined(foo)
+ EOI
+
+ : false
+ :
+ $* <<EOI >'false'
+ print $defined(foo)
+ EOI
+}
+
: type
:
{
@@ -93,9 +110,7 @@
<stdin>:1:8: error: unmatched call to getenv()
/((
info: candidate: getenv(<untyped>), qualified name builtin.getenv
- info: candidate: getenv(string), qualified name builtin.getenv
/)|(
- info: candidate: getenv(string), qualified name builtin.getenv
info: candidate: getenv(<untyped>), qualified name builtin.getenv
/))
EOE