mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-05 21:31:08 -06:00
Refactor: Introduce cmArgumentList container class
The `cmArgumentList` has been turned into a class (forward declared in the header). It inherits from the `std::list` (yeah, but we don't intend to store polymorphic classes in it). In addition to the standard methods, now it's possible to move `HandlePredicate` (renamed to `ReduceOneArg`) and `HandleBinaryOp` (renamed to `ReduceTwoArgs`) as its members. Additionally, iterators managements (`IncrementArguments`) have been refactored into two separate classes mimicking iterators. This also allows having a uniform `for` loop and concentrates the logic of iterators advancing in it instead of the loop's body. The arguments processing algorithms operate with "windows" over a collection of arguments. Hence there are two kinds of "iteration windows" -- allowing to observe 2 or 3 elements per loop iteration. These iteration "windows" also passed to reducers.
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <list>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
|
|
||||||
#include "cmsys/RegularExpression.hxx"
|
#include "cmsys/RegularExpression.hxx"
|
||||||
|
|
||||||
|
#include "cmExpandedCommandArgument.h"
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
#include "cmMessageType.h"
|
#include "cmMessageType.h"
|
||||||
#include "cmProperty.h"
|
#include "cmProperty.h"
|
||||||
@@ -89,47 +91,103 @@ std::string bool2string(bool const value)
|
|||||||
{
|
{
|
||||||
return std::string(std::size_t(1), static_cast<char>('0' + int(value)));
|
return std::string(std::size_t(1), static_cast<char>('0' + int(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncrementArguments(cmConditionEvaluator::cmArgumentList& newArgs,
|
|
||||||
cmConditionEvaluator::cmArgumentList::iterator& argP1)
|
|
||||||
{
|
|
||||||
using difference_type =
|
|
||||||
cmConditionEvaluator::cmArgumentList::difference_type;
|
|
||||||
std::advance(argP1, difference_type(argP1 != newArgs.end()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IncrementArguments(cmConditionEvaluator::cmArgumentList& newArgs,
|
|
||||||
cmConditionEvaluator::cmArgumentList::iterator& argP1,
|
|
||||||
cmConditionEvaluator::cmArgumentList::iterator& argP2)
|
|
||||||
{
|
|
||||||
IncrementArguments(newArgs, argP1);
|
|
||||||
argP2 = argP1;
|
|
||||||
using difference_type =
|
|
||||||
cmConditionEvaluator::cmArgumentList::difference_type;
|
|
||||||
std::advance(argP2, difference_type(argP1 != newArgs.end()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandlePredicate(const bool value,
|
|
||||||
cmConditionEvaluator::cmArgumentList& newArgs,
|
|
||||||
cmConditionEvaluator::cmArgumentList::iterator arg,
|
|
||||||
cmConditionEvaluator::cmArgumentList::iterator argP1)
|
|
||||||
{
|
|
||||||
*arg = cmExpandedCommandArgument(bool2string(value), true);
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleBinaryOp(const bool value,
|
|
||||||
cmConditionEvaluator::cmArgumentList& newArgs,
|
|
||||||
cmConditionEvaluator::cmArgumentList::iterator arg,
|
|
||||||
cmConditionEvaluator::cmArgumentList::iterator argP1,
|
|
||||||
cmConditionEvaluator::cmArgumentList::iterator argP2)
|
|
||||||
{
|
|
||||||
*arg = cmExpandedCommandArgument(bool2string(value), true);
|
|
||||||
newArgs.erase(argP2);
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
}
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
#if defined(__SUNPRO_CC)
|
||||||
|
# define CM_INHERIT_CTOR(Class, Base, Tpl) \
|
||||||
|
template <typename... Args> \
|
||||||
|
Class(Args&&... args) \
|
||||||
|
: Base Tpl(std::forward<Args>(args)...) \
|
||||||
|
{ \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define CM_INHERIT_CTOR(Class, Base, Tpl) using Base Tpl ::Base;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// BEGIN cmConditionEvaluator::cmArgumentList
|
||||||
|
class cmConditionEvaluator::cmArgumentList
|
||||||
|
: public std::list<cmExpandedCommandArgument>
|
||||||
|
{
|
||||||
|
using base_t = std::list<cmExpandedCommandArgument>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CM_INHERIT_CTOR(cmArgumentList, list, <cmExpandedCommandArgument>);
|
||||||
|
|
||||||
|
class CurrentAndNextIter
|
||||||
|
{
|
||||||
|
friend class cmConditionEvaluator::cmArgumentList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
base_t::iterator current;
|
||||||
|
base_t::iterator next;
|
||||||
|
|
||||||
|
CurrentAndNextIter advance(base_t& args)
|
||||||
|
{
|
||||||
|
this->current = std::next(this->current);
|
||||||
|
this->next =
|
||||||
|
std::next(this->current, difference_type(this->current != args.end()));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CurrentAndNextIter(base_t& args)
|
||||||
|
: current(args.begin())
|
||||||
|
, next(std::next(this->current,
|
||||||
|
difference_type(this->current != args.end())))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CurrentAndTwoMoreIter
|
||||||
|
{
|
||||||
|
friend class cmConditionEvaluator::cmArgumentList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
base_t::iterator current;
|
||||||
|
base_t::iterator next;
|
||||||
|
base_t::iterator nextnext;
|
||||||
|
|
||||||
|
CurrentAndTwoMoreIter advance(base_t& args)
|
||||||
|
{
|
||||||
|
this->current = std::next(this->current);
|
||||||
|
this->next =
|
||||||
|
std::next(this->current, difference_type(this->current != args.end()));
|
||||||
|
this->nextnext =
|
||||||
|
std::next(this->next, difference_type(this->next != args.end()));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CurrentAndTwoMoreIter(base_t& args)
|
||||||
|
: current(args.begin())
|
||||||
|
, next(std::next(this->current,
|
||||||
|
difference_type(this->current != args.end())))
|
||||||
|
, nextnext(
|
||||||
|
std::next(this->next, difference_type(this->next != args.end())))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CurrentAndNextIter make2ArgsIterator() { return *this; }
|
||||||
|
CurrentAndTwoMoreIter make3ArgsIterator() { return *this; }
|
||||||
|
|
||||||
|
template <typename Iter>
|
||||||
|
void ReduceOneArg(const bool value, Iter args)
|
||||||
|
{
|
||||||
|
*args.current = cmExpandedCommandArgument(bool2string(value), true);
|
||||||
|
this->erase(args.next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReduceTwoArgs(const bool value, CurrentAndTwoMoreIter args)
|
||||||
|
{
|
||||||
|
*args.current = cmExpandedCommandArgument(bool2string(value), true);
|
||||||
|
this->erase(args.nextnext);
|
||||||
|
this->erase(args.next);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// END cmConditionEvaluator::cmArgumentList
|
||||||
|
|
||||||
cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile,
|
cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile,
|
||||||
cmListFileBacktrace bt)
|
cmListFileBacktrace bt)
|
||||||
: Makefile(makefile)
|
: Makefile(makefile)
|
||||||
@@ -455,15 +513,13 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&,
|
|||||||
const auto policy64IsOld = this->Policy64Status == cmPolicies::OLD ||
|
const auto policy64IsOld = this->Policy64Status == cmPolicies::OLD ||
|
||||||
this->Policy64Status == cmPolicies::WARN;
|
this->Policy64Status == cmPolicies::WARN;
|
||||||
|
|
||||||
for (auto arg = newArgs.begin(), argP1 = arg; arg != newArgs.end();
|
for (auto args = newArgs.make2ArgsIterator(); args.current != newArgs.end();
|
||||||
argP1 = ++arg) {
|
args.advance(newArgs)) {
|
||||||
|
|
||||||
IncrementArguments(newArgs, argP1);
|
|
||||||
|
|
||||||
auto policyCheck = [&, this](const cmPolicies::PolicyID id,
|
auto policyCheck = [&, this](const cmPolicies::PolicyID id,
|
||||||
const cmPolicies::PolicyStatus status,
|
const cmPolicies::PolicyStatus status,
|
||||||
const cm::static_string_view kw) {
|
const cm::static_string_view kw) {
|
||||||
if (status == cmPolicies::WARN && this->IsKeyword(kw, *arg)) {
|
if (status == cmPolicies::WARN && this->IsKeyword(kw, *args.current)) {
|
||||||
std::ostringstream e;
|
std::ostringstream e;
|
||||||
e << cmPolicies::GetPolicyWarning(id) << "\n"
|
e << cmPolicies::GetPolicyWarning(id) << "\n"
|
||||||
<< kw
|
<< kw
|
||||||
@@ -481,73 +537,72 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&,
|
|||||||
|
|
||||||
// NOTE Fail fast: All the predicates below require the next arg to be
|
// NOTE Fail fast: All the predicates below require the next arg to be
|
||||||
// valid
|
// valid
|
||||||
if (argP1 == newArgs.end()) {
|
if (args.next == newArgs.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// does a file exist
|
// does a file exist
|
||||||
if (this->IsKeyword(keyEXISTS, *arg)) {
|
if (this->IsKeyword(keyEXISTS, *args.current)) {
|
||||||
HandlePredicate(cmSystemTools::FileExists(argP1->GetValue()), newArgs,
|
newArgs.ReduceOneArg(cmSystemTools::FileExists(args.next->GetValue()),
|
||||||
arg, argP1);
|
args);
|
||||||
}
|
}
|
||||||
// does a directory with this name exist
|
// does a directory with this name exist
|
||||||
else if (this->IsKeyword(keyIS_DIRECTORY, *arg)) {
|
else if (this->IsKeyword(keyIS_DIRECTORY, *args.current)) {
|
||||||
HandlePredicate(cmSystemTools::FileIsDirectory(argP1->GetValue()),
|
newArgs.ReduceOneArg(
|
||||||
newArgs, arg, argP1);
|
cmSystemTools::FileIsDirectory(args.next->GetValue()), args);
|
||||||
}
|
}
|
||||||
// does a symlink with this name exist
|
// does a symlink with this name exist
|
||||||
else if (this->IsKeyword(keyIS_SYMLINK, *arg)) {
|
else if (this->IsKeyword(keyIS_SYMLINK, *args.current)) {
|
||||||
HandlePredicate(cmSystemTools::FileIsSymlink(argP1->GetValue()), newArgs,
|
newArgs.ReduceOneArg(cmSystemTools::FileIsSymlink(args.next->GetValue()),
|
||||||
arg, argP1);
|
args);
|
||||||
}
|
}
|
||||||
// is the given path an absolute path ?
|
// is the given path an absolute path ?
|
||||||
else if (this->IsKeyword(keyIS_ABSOLUTE, *arg)) {
|
else if (this->IsKeyword(keyIS_ABSOLUTE, *args.current)) {
|
||||||
HandlePredicate(cmSystemTools::FileIsFullPath(argP1->GetValue()),
|
newArgs.ReduceOneArg(
|
||||||
newArgs, arg, argP1);
|
cmSystemTools::FileIsFullPath(args.next->GetValue()), args);
|
||||||
}
|
}
|
||||||
// does a command exist
|
// does a command exist
|
||||||
else if (this->IsKeyword(keyCOMMAND, *arg)) {
|
else if (this->IsKeyword(keyCOMMAND, *args.current)) {
|
||||||
HandlePredicate(
|
newArgs.ReduceOneArg(
|
||||||
this->Makefile.GetState()->GetCommand(argP1->GetValue()) != nullptr,
|
bool(this->Makefile.GetState()->GetCommand(args.next->GetValue())),
|
||||||
newArgs, arg, argP1);
|
args);
|
||||||
}
|
}
|
||||||
// does a policy exist
|
// does a policy exist
|
||||||
else if (this->IsKeyword(keyPOLICY, *arg)) {
|
else if (this->IsKeyword(keyPOLICY, *args.current)) {
|
||||||
cmPolicies::PolicyID pid;
|
cmPolicies::PolicyID pid;
|
||||||
HandlePredicate(cmPolicies::GetPolicyID(argP1->GetValue().c_str(), pid),
|
newArgs.ReduceOneArg(
|
||||||
newArgs, arg, argP1);
|
cmPolicies::GetPolicyID(args.next->GetValue().c_str(), pid), args);
|
||||||
}
|
}
|
||||||
// does a target exist
|
// does a target exist
|
||||||
else if (this->IsKeyword(keyTARGET, *arg)) {
|
else if (this->IsKeyword(keyTARGET, *args.current)) {
|
||||||
HandlePredicate(this->Makefile.FindTargetToUse(argP1->GetValue()) !=
|
newArgs.ReduceOneArg(
|
||||||
nullptr,
|
bool(this->Makefile.FindTargetToUse(args.next->GetValue())), args);
|
||||||
newArgs, arg, argP1);
|
|
||||||
}
|
}
|
||||||
// is a variable defined
|
// is a variable defined
|
||||||
else if (this->IsKeyword(keyDEFINED, *arg)) {
|
else if (this->IsKeyword(keyDEFINED, *args.current)) {
|
||||||
const auto argP1len = argP1->GetValue().size();
|
const auto argP1len = args.next->GetValue().size();
|
||||||
auto bdef = false;
|
auto bdef = false;
|
||||||
if (argP1len > 4 && cmHasLiteralPrefix(argP1->GetValue(), "ENV{") &&
|
if (argP1len > 4 && cmHasLiteralPrefix(args.next->GetValue(), "ENV{") &&
|
||||||
argP1->GetValue().operator[](argP1len - 1) == '}') {
|
args.next->GetValue().operator[](argP1len - 1) == '}') {
|
||||||
const auto env = argP1->GetValue().substr(4, argP1len - 5);
|
const auto env = args.next->GetValue().substr(4, argP1len - 5);
|
||||||
bdef = cmSystemTools::HasEnv(env);
|
bdef = cmSystemTools::HasEnv(env);
|
||||||
} else if (argP1len > 6 &&
|
} else if (argP1len > 6 &&
|
||||||
cmHasLiteralPrefix(argP1->GetValue(), "CACHE{") &&
|
cmHasLiteralPrefix(args.next->GetValue(), "CACHE{") &&
|
||||||
argP1->GetValue().operator[](argP1len - 1) == '}') {
|
args.next->GetValue().operator[](argP1len - 1) == '}') {
|
||||||
const auto cache = argP1->GetValue().substr(6, argP1len - 7);
|
const auto cache = args.next->GetValue().substr(6, argP1len - 7);
|
||||||
bdef = this->Makefile.GetState()->GetCacheEntryValue(cache) != nullptr;
|
bdef = bool(this->Makefile.GetState()->GetCacheEntryValue(cache));
|
||||||
} else {
|
} else {
|
||||||
bdef = this->Makefile.IsDefinitionSet(argP1->GetValue());
|
bdef = this->Makefile.IsDefinitionSet(args.next->GetValue());
|
||||||
}
|
}
|
||||||
HandlePredicate(bdef, newArgs, arg, argP1);
|
newArgs.ReduceOneArg(bdef, args);
|
||||||
}
|
}
|
||||||
// does a test exist
|
// does a test exist
|
||||||
else if (this->IsKeyword(keyTEST, *arg)) {
|
else if (this->IsKeyword(keyTEST, *args.current)) {
|
||||||
if (policy64IsOld) {
|
if (policy64IsOld) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
HandlePredicate(this->Makefile.GetTest(argP1->GetValue()) != nullptr,
|
newArgs.ReduceOneArg(bool(this->Makefile.GetTest(args.next->GetValue())),
|
||||||
newArgs, arg, argP1);
|
args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -559,32 +614,32 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
|
|||||||
std::string& errorString,
|
std::string& errorString,
|
||||||
MessageType& status)
|
MessageType& status)
|
||||||
{
|
{
|
||||||
for (auto arg = newArgs.begin(), argP1 = arg, argP2 = arg;
|
for (auto args = newArgs.make3ArgsIterator(); args.current != newArgs.end();
|
||||||
arg != newArgs.end(); argP1 = ++arg) {
|
args.advance(newArgs)) {
|
||||||
|
|
||||||
IncrementArguments(newArgs, argP1, argP2);
|
|
||||||
|
|
||||||
int matchNo;
|
int matchNo;
|
||||||
|
|
||||||
// NOTE Handle special case `if(... BLAH_BAH MATCHES)`
|
// NOTE Handle special case `if(... BLAH_BLAH MATCHES)`
|
||||||
// (i.e., w/o regex to match which is possibly result of
|
// (i.e., w/o regex to match which is possibly result of
|
||||||
// variable expansion to an empty string)
|
// variable expansion to an empty string)
|
||||||
if (argP1 != newArgs.end() && this->IsKeyword(keyMATCHES, *arg)) {
|
if (args.next != newArgs.end() &&
|
||||||
HandlePredicate(false, newArgs, arg, argP1);
|
this->IsKeyword(keyMATCHES, *args.current)) {
|
||||||
|
newArgs.ReduceOneArg(false, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE Fail fast: All the binary ops below require 2 arguments.
|
// NOTE Fail fast: All the binary ops below require 2 arguments.
|
||||||
else if (argP1 == newArgs.end() || argP2 == newArgs.end()) {
|
else if (args.next == newArgs.end() || args.nextnext == newArgs.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (this->IsKeyword(keyMATCHES, *argP1)) {
|
else if (this->IsKeyword(keyMATCHES, *args.next)) {
|
||||||
cmProp def = this->GetDefinitionIfUnquoted(*arg);
|
cmProp def = this->GetDefinitionIfUnquoted(*args.current);
|
||||||
|
|
||||||
std::string def_buf;
|
std::string def_buf;
|
||||||
if (!def) {
|
if (!def) {
|
||||||
def = &arg->GetValue();
|
def = &args.current->GetValue();
|
||||||
} else if (cmHasLiteralPrefix(arg->GetValue(), "CMAKE_MATCH_")) {
|
} else if (cmHasLiteralPrefix(args.current->GetValue(),
|
||||||
|
"CMAKE_MATCH_")) {
|
||||||
// The string to match is owned by our match result variables.
|
// The string to match is owned by our match result variables.
|
||||||
// Move it to our own buffer before clearing them.
|
// Move it to our own buffer before clearing them.
|
||||||
def_buf = *def;
|
def_buf = *def;
|
||||||
@@ -593,7 +648,7 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
|
|||||||
|
|
||||||
this->Makefile.ClearMatches();
|
this->Makefile.ClearMatches();
|
||||||
|
|
||||||
const auto& rex = argP2->GetValue();
|
const auto& rex = args.nextnext->GetValue();
|
||||||
cmsys::RegularExpression regEntry;
|
cmsys::RegularExpression regEntry;
|
||||||
if (!regEntry.compile(rex)) {
|
if (!regEntry.compile(rex)) {
|
||||||
std::ostringstream error;
|
std::ostringstream error;
|
||||||
@@ -607,15 +662,15 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
|
|||||||
if (match) {
|
if (match) {
|
||||||
this->Makefile.StoreMatches(regEntry);
|
this->Makefile.StoreMatches(regEntry);
|
||||||
}
|
}
|
||||||
HandleBinaryOp(match, newArgs, arg, argP1, argP2);
|
newArgs.ReduceTwoArgs(match, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((matchNo =
|
else if ((matchNo =
|
||||||
this->matchKeys(*argP1, keyLESS, keyLESS_EQUAL, keyGREATER,
|
this->matchKeys(*args.next, keyLESS, keyLESS_EQUAL, keyGREATER,
|
||||||
keyGREATER_EQUAL, keyEQUAL))) {
|
keyGREATER_EQUAL, keyEQUAL))) {
|
||||||
|
|
||||||
cmProp ldef = this->GetVariableOrString(*arg);
|
cmProp ldef = this->GetVariableOrString(*args.current);
|
||||||
cmProp rdef = this->GetVariableOrString(*argP2);
|
cmProp rdef = this->GetVariableOrString(*args.nextnext);
|
||||||
|
|
||||||
double lhs;
|
double lhs;
|
||||||
double rhs;
|
double rhs;
|
||||||
@@ -623,23 +678,23 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
|
|||||||
return std::sscanf(ldef->c_str(), "%lg", &lhs) == 1 &&
|
return std::sscanf(ldef->c_str(), "%lg", &lhs) == 1 &&
|
||||||
std::sscanf(rdef->c_str(), "%lg", &rhs) == 1;
|
std::sscanf(rdef->c_str(), "%lg", &rhs) == 1;
|
||||||
};
|
};
|
||||||
|
// clang-format off
|
||||||
const auto result = parseDoubles() &&
|
const auto result = parseDoubles() &&
|
||||||
// clang-format off
|
|
||||||
cmRt2CtSelector<
|
cmRt2CtSelector<
|
||||||
std::less, std::less_equal,
|
std::less, std::less_equal,
|
||||||
std::greater, std::greater_equal,
|
std::greater, std::greater_equal,
|
||||||
std::equal_to
|
std::equal_to
|
||||||
>::eval(matchNo, lhs, rhs);
|
>::eval(matchNo, lhs, rhs);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
HandleBinaryOp(result, newArgs, arg, argP1, argP2);
|
newArgs.ReduceTwoArgs(result, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((matchNo = this->matchKeys(*argP1, keySTRLESS, keySTRLESS_EQUAL,
|
else if ((matchNo = this->matchKeys(*args.next, keySTRLESS,
|
||||||
keySTRGREATER, keySTRGREATER_EQUAL,
|
keySTRLESS_EQUAL, keySTRGREATER,
|
||||||
keySTREQUAL))) {
|
keySTRGREATER_EQUAL, keySTREQUAL))) {
|
||||||
|
|
||||||
const cmProp lhs = this->GetVariableOrString(*arg);
|
const cmProp lhs = this->GetVariableOrString(*args.current);
|
||||||
const cmProp rhs = this->GetVariableOrString(*argP2);
|
const cmProp rhs = this->GetVariableOrString(*args.nextnext);
|
||||||
const auto val = (*lhs).compare(*rhs);
|
const auto val = (*lhs).compare(*rhs);
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const auto result = cmRt2CtSelector<
|
const auto result = cmRt2CtSelector<
|
||||||
@@ -648,45 +703,46 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
|
|||||||
std::equal_to
|
std::equal_to
|
||||||
>::eval(matchNo, val, 0);
|
>::eval(matchNo, val, 0);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
HandleBinaryOp(result, newArgs, arg, argP1, argP2);
|
newArgs.ReduceTwoArgs(result, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((matchNo =
|
else if ((matchNo =
|
||||||
this->matchKeys(*argP1, keyVERSION_LESS, keyVERSION_LESS_EQUAL,
|
this->matchKeys(*args.next, keyVERSION_LESS,
|
||||||
keyVERSION_GREATER, keyVERSION_GREATER_EQUAL,
|
keyVERSION_LESS_EQUAL, keyVERSION_GREATER,
|
||||||
keyVERSION_EQUAL))) {
|
keyVERSION_GREATER_EQUAL, keyVERSION_EQUAL))) {
|
||||||
|
|
||||||
const cmSystemTools::CompareOp xlat[5] = {
|
const cmSystemTools::CompareOp xlat[5] = {
|
||||||
cmSystemTools::OP_LESS, cmSystemTools::OP_LESS_EQUAL,
|
cmSystemTools::OP_LESS, cmSystemTools::OP_LESS_EQUAL,
|
||||||
cmSystemTools::OP_GREATER, cmSystemTools::OP_GREATER_EQUAL,
|
cmSystemTools::OP_GREATER, cmSystemTools::OP_GREATER_EQUAL,
|
||||||
cmSystemTools::OP_EQUAL
|
cmSystemTools::OP_EQUAL
|
||||||
};
|
};
|
||||||
const auto op = xlat[matchNo - 1];
|
const auto op = xlat[matchNo - 1];
|
||||||
const cmProp lhs = this->GetVariableOrString(*arg);
|
const cmProp lhs = this->GetVariableOrString(*args.current);
|
||||||
const cmProp rhs = this->GetVariableOrString(*argP2);
|
const cmProp rhs = this->GetVariableOrString(*args.nextnext);
|
||||||
const auto result =
|
const auto result =
|
||||||
cmSystemTools::VersionCompare(op, lhs->c_str(), rhs->c_str());
|
cmSystemTools::VersionCompare(op, lhs->c_str(), rhs->c_str());
|
||||||
HandleBinaryOp(result, newArgs, arg, argP1, argP2);
|
newArgs.ReduceTwoArgs(result, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// is file A newer than file B
|
// is file A newer than file B
|
||||||
else if (this->IsKeyword(keyIS_NEWER_THAN, *argP1)) {
|
else if (this->IsKeyword(keyIS_NEWER_THAN, *args.next)) {
|
||||||
auto fileIsNewer = 0;
|
auto fileIsNewer = 0;
|
||||||
cmsys::Status ftcStatus = cmSystemTools::FileTimeCompare(
|
cmsys::Status ftcStatus = cmSystemTools::FileTimeCompare(
|
||||||
arg->GetValue(), argP2->GetValue(), &fileIsNewer);
|
args.current->GetValue(), args.nextnext->GetValue(), &fileIsNewer);
|
||||||
HandleBinaryOp((!ftcStatus || fileIsNewer == 1 || fileIsNewer == 0),
|
newArgs.ReduceTwoArgs(
|
||||||
newArgs, arg, argP1, argP2);
|
(!ftcStatus || fileIsNewer == 1 || fileIsNewer == 0), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (this->IsKeyword(keyIN_LIST, *argP1)) {
|
else if (this->IsKeyword(keyIN_LIST, *args.next)) {
|
||||||
|
|
||||||
if (this->Policy57Status != cmPolicies::OLD &&
|
if (this->Policy57Status != cmPolicies::OLD &&
|
||||||
this->Policy57Status != cmPolicies::WARN) {
|
this->Policy57Status != cmPolicies::WARN) {
|
||||||
|
|
||||||
cmProp def = this->GetVariableOrString(*arg);
|
cmProp def = this->GetVariableOrString(*args.current);
|
||||||
cmProp def2 = this->Makefile.GetDefinition(argP2->GetValue());
|
cmProp def2 = this->Makefile.GetDefinition(args.nextnext->GetValue());
|
||||||
|
|
||||||
HandleBinaryOp(def2 && cm::contains(cmExpandedList(*def2, true), *def),
|
newArgs.ReduceTwoArgs(
|
||||||
newArgs, arg, argP1, argP2);
|
def2 && cm::contains(cmExpandedList(*def2, true), *def), args);
|
||||||
} else if (this->Policy57Status == cmPolicies::WARN) {
|
} else if (this->Policy57Status == cmPolicies::WARN) {
|
||||||
std::ostringstream e;
|
std::ostringstream e;
|
||||||
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057)
|
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057)
|
||||||
@@ -708,15 +764,12 @@ bool cmConditionEvaluator::HandleLevel3(cmArgumentList& newArgs,
|
|||||||
std::string& errorString,
|
std::string& errorString,
|
||||||
MessageType& status)
|
MessageType& status)
|
||||||
{
|
{
|
||||||
for (auto arg = newArgs.begin(), argP1 = arg; arg != newArgs.end();
|
for (auto args = newArgs.make2ArgsIterator(); args.next != newArgs.end();
|
||||||
argP1 = ++arg) {
|
args.advance(newArgs)) {
|
||||||
|
if (this->IsKeyword(keyNOT, *args.current)) {
|
||||||
IncrementArguments(newArgs, argP1);
|
const auto rhs = this->GetBooleanValueWithAutoDereference(
|
||||||
|
*args.next, errorString, status);
|
||||||
if (argP1 != newArgs.end() && this->IsKeyword(keyNOT, *arg)) {
|
newArgs.ReduceOneArg(!rhs, args);
|
||||||
const auto rhs =
|
|
||||||
this->GetBooleanValueWithAutoDereference(*argP1, errorString, status);
|
|
||||||
HandlePredicate(!rhs, newArgs, arg, argP1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -728,20 +781,23 @@ bool cmConditionEvaluator::HandleLevel4(cmArgumentList& newArgs,
|
|||||||
std::string& errorString,
|
std::string& errorString,
|
||||||
MessageType& status)
|
MessageType& status)
|
||||||
{
|
{
|
||||||
for (auto arg = newArgs.begin(), argP1 = arg, argP2 = arg;
|
for (auto args = newArgs.make3ArgsIterator(); args.nextnext != newArgs.end();
|
||||||
arg != newArgs.end(); argP1 = ++arg) {
|
args.advance(newArgs)) {
|
||||||
|
|
||||||
IncrementArguments(newArgs, argP1, argP2);
|
int matchNo;
|
||||||
|
|
||||||
if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
|
if ((matchNo = this->matchKeys(*args.next, keyAND, keyOR))) {
|
||||||
(this->IsKeyword(keyAND, *argP1) || this->IsKeyword(keyOR, *argP1))) {
|
const auto lhs = this->GetBooleanValueWithAutoDereference(
|
||||||
const auto lhs =
|
*args.current, errorString, status);
|
||||||
this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
|
const auto rhs = this->GetBooleanValueWithAutoDereference(
|
||||||
const auto rhs =
|
*args.nextnext, errorString, status);
|
||||||
this->GetBooleanValueWithAutoDereference(*argP2, errorString, status);
|
// clang-format off
|
||||||
HandleBinaryOp(this->IsKeyword(keyAND, *argP1) ? (lhs && rhs)
|
const auto result =
|
||||||
: (lhs || rhs),
|
cmRt2CtSelector<
|
||||||
newArgs, arg, argP1, argP2);
|
std::logical_and, std::logical_or
|
||||||
|
>::eval(matchNo, lhs, rhs);
|
||||||
|
// clang-format on
|
||||||
|
newArgs.ReduceTwoArgs(result, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -4,25 +4,22 @@
|
|||||||
|
|
||||||
#include "cmConfigure.h" // IWYU pragma: keep
|
#include "cmConfigure.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cmext/string_view>
|
#include <cmext/string_view>
|
||||||
|
|
||||||
#include "cmExpandedCommandArgument.h"
|
|
||||||
#include "cmListFileCache.h"
|
#include "cmListFileCache.h"
|
||||||
#include "cmMessageType.h"
|
#include "cmMessageType.h"
|
||||||
#include "cmPolicies.h"
|
#include "cmPolicies.h"
|
||||||
#include "cmProperty.h"
|
#include "cmProperty.h"
|
||||||
|
|
||||||
|
class cmExpandedCommandArgument;
|
||||||
class cmMakefile;
|
class cmMakefile;
|
||||||
|
|
||||||
class cmConditionEvaluator
|
class cmConditionEvaluator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using cmArgumentList = std::list<cmExpandedCommandArgument>;
|
|
||||||
|
|
||||||
cmConditionEvaluator(cmMakefile& makefile, cmListFileBacktrace bt);
|
cmConditionEvaluator(cmMakefile& makefile, cmListFileBacktrace bt);
|
||||||
|
|
||||||
// this is a shared function for both If and Else to determine if the
|
// this is a shared function for both If and Else to determine if the
|
||||||
@@ -32,6 +29,8 @@ public:
|
|||||||
std::string& errorString, MessageType& status);
|
std::string& errorString, MessageType& status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class cmArgumentList;
|
||||||
|
|
||||||
// Filter the given variable definition based on policy CMP0054.
|
// Filter the given variable definition based on policy CMP0054.
|
||||||
cmProp GetDefinitionIfUnquoted(
|
cmProp GetDefinitionIfUnquoted(
|
||||||
const cmExpandedCommandArgument& argument) const;
|
const cmExpandedCommandArgument& argument) const;
|
||||||
@@ -51,6 +50,15 @@ private:
|
|||||||
MessageType& status,
|
MessageType& status,
|
||||||
bool oneArg = false) const;
|
bool oneArg = false) const;
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
int matchKeysImpl(const cmExpandedCommandArgument&);
|
||||||
|
|
||||||
|
template <int N, typename T, typename... Keys>
|
||||||
|
int matchKeysImpl(const cmExpandedCommandArgument&, T, Keys...);
|
||||||
|
|
||||||
|
template <typename... Keys>
|
||||||
|
int matchKeys(const cmExpandedCommandArgument&, Keys...);
|
||||||
|
|
||||||
bool HandleLevel0(cmArgumentList& newArgs, std::string& errorString,
|
bool HandleLevel0(cmArgumentList& newArgs, std::string& errorString,
|
||||||
MessageType& status);
|
MessageType& status);
|
||||||
|
|
||||||
@@ -65,15 +73,6 @@ private:
|
|||||||
bool HandleLevel4(cmArgumentList& newArgs, std::string& errorString,
|
bool HandleLevel4(cmArgumentList& newArgs, std::string& errorString,
|
||||||
MessageType& status);
|
MessageType& status);
|
||||||
|
|
||||||
template <int N>
|
|
||||||
int matchKeysImpl(const cmExpandedCommandArgument&);
|
|
||||||
|
|
||||||
template <int N, typename T, typename... Keys>
|
|
||||||
int matchKeysImpl(const cmExpandedCommandArgument&, T, Keys...);
|
|
||||||
|
|
||||||
template <typename... Keys>
|
|
||||||
int matchKeys(const cmExpandedCommandArgument&, Keys...);
|
|
||||||
|
|
||||||
cmMakefile& Makefile;
|
cmMakefile& Makefile;
|
||||||
cmListFileBacktrace Backtrace;
|
cmListFileBacktrace Backtrace;
|
||||||
cmPolicies::PolicyStatus Policy12Status;
|
cmPolicies::PolicyStatus Policy12Status;
|
||||||
|
|||||||
6
Tests/RunCMake/if/IncompleteMatches-stdout.txt
Normal file
6
Tests/RunCMake/if/IncompleteMatches-stdout.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
-- Test #1 passed
|
||||||
|
-- Test #2 passed
|
||||||
|
-- Test #3 passed
|
||||||
|
-- Test #4 passed
|
||||||
|
-- Test #5 passed
|
||||||
|
-- Test #6 passed
|
||||||
36
Tests/RunCMake/if/IncompleteMatches.cmake
Normal file
36
Tests/RunCMake/if/IncompleteMatches.cmake
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
if(MATCHES)
|
||||||
|
message(SEND_ERROR "Test #1 failed")
|
||||||
|
else()
|
||||||
|
message(STATUS "Test #1 passed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("" MATCHES "")
|
||||||
|
message(STATUS "Test #2 passed")
|
||||||
|
else()
|
||||||
|
message(SEND_ERROR "Test #2 failed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MATCHES RHS)
|
||||||
|
message(SEND_ERROR "Test #3 failed")
|
||||||
|
else()
|
||||||
|
message(STATUS "Test #3 passed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(RHS "")
|
||||||
|
if(MATCHES RHS)
|
||||||
|
message(SEND_ERROR "Test #4 failed")
|
||||||
|
else()
|
||||||
|
message(STATUS "Test #4 passed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MATCHES "^$")
|
||||||
|
message(SEND_ERROR "Test #5 failed")
|
||||||
|
else()
|
||||||
|
message(STATUS "Test #5 passed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("" MATCHES "^$")
|
||||||
|
message(STATUS "Test #6 passed")
|
||||||
|
else()
|
||||||
|
message(SEND_ERROR "Test #6 failed")
|
||||||
|
endif()
|
||||||
1
Tests/RunCMake/if/IncompleteMatchesFail-result.txt
Normal file
1
Tests/RunCMake/if/IncompleteMatchesFail-result.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1
|
||||||
6
Tests/RunCMake/if/IncompleteMatchesFail-stderr.txt
Normal file
6
Tests/RunCMake/if/IncompleteMatchesFail-stderr.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
CMake Error at IncompleteMatchesFail\.cmake:1 \(if\):
|
||||||
|
if given arguments:
|
||||||
|
|
||||||
|
"LHS" "MATCHES"
|
||||||
|
|
||||||
|
Unknown arguments specified
|
||||||
2
Tests/RunCMake/if/IncompleteMatchesFail.cmake
Normal file
2
Tests/RunCMake/if/IncompleteMatchesFail.cmake
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
if(LHS MATCHES)
|
||||||
|
endif()
|
||||||
@@ -10,6 +10,8 @@ run_cmake(elseif-message)
|
|||||||
run_cmake(misplaced-elseif)
|
run_cmake(misplaced-elseif)
|
||||||
|
|
||||||
run_cmake(MatchesSelf)
|
run_cmake(MatchesSelf)
|
||||||
|
run_cmake(IncompleteMatches)
|
||||||
|
run_cmake(IncompleteMatchesFail)
|
||||||
|
|
||||||
run_cmake(TestNameThatExists)
|
run_cmake(TestNameThatExists)
|
||||||
run_cmake(TestNameThatDoesNotExist)
|
run_cmake(TestNameThatDoesNotExist)
|
||||||
|
|||||||
Reference in New Issue
Block a user