diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2020-03-17 07:33:41 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2020-03-17 07:47:17 +0200 |
commit | bab021a6203127f38fb89c61cc41deb3e0abbe62 (patch) | |
tree | 868ddce415b985636baed5dd566ec4bd11f67c99 | |
parent | 962f83b1e551cc683f1052d32cb79b969e65af5f (diff) |
Add $defined(<variable>) function
-rw-r--r-- | libbuild2/function.cxx | 9 | ||||
-rw-r--r-- | libbuild2/function.hxx | 11 | ||||
-rw-r--r-- | libbuild2/functions-builtin.cxx | 46 | ||||
-rw-r--r-- | tests/function/builtin/testscript | 19 |
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 |