GenEx LIST: list operations

Fixes: #24550, #24547
This commit is contained in:
Marc Chevrier
2023-04-04 16:42:58 +02:00
parent e256e35daa
commit 31675964e7
152 changed files with 2382 additions and 37 deletions

View File

@@ -188,7 +188,7 @@ For more information on regular expressions look under
.. versionadded:: 3.12
Transforms the list by applying an action to all or, by specifying a
Transforms the list by applying an ``<ACTION>`` to all or, by specifying a
``<SELECTOR>``, to the selected elements of the list, storing the result
in-place or in the specified output variable.
@@ -205,42 +205,42 @@ For more information on regular expressions look under
:command:`APPEND <string(APPEND)>`, :command:`PREPEND <string(PREPEND)>`
Append, prepend specified value to each element of the list.
.. code-block:: cmake
.. signature::
list(TRANSFORM <list> (APPEND|PREPEND) <value> ...)
:target: TRANSFORM_APPEND
list(TRANSFORM <list> <APPEND|PREPEND> <value> ...)
:command:`TOLOWER <string(TOLOWER)>`, :command:`TOUPPER <string(TOUPPER)>`
Convert each element of the list to lower, upper characters.
:command:`TOUPPER <string(TOUPPER)>`, :command:`TOLOWER <string(TOLOWER)>`
Convert each element of the list to upper, lower characters.
.. code-block:: cmake
list(TRANSFORM <list> <TOLOWER|TOUPPER> ...)
.. signature::
list(TRANSFORM <list> (TOLOWER|TOUPPER) ...)
:target: TRANSFORM_TOLOWER
:command:`STRIP <string(STRIP)>`
Remove leading and trailing spaces from each element of the list.
.. code-block:: cmake
.. signature::
list(TRANSFORM <list> STRIP ...)
:target: TRANSFORM_STRIP
:command:`GENEX_STRIP <string(GENEX_STRIP)>`
Strip any
:manual:`generator expressions <cmake-generator-expressions(7)>`
from each element of the list.
.. code-block:: cmake
.. signature::
list(TRANSFORM <list> GENEX_STRIP ...)
:target: TRANSFORM_GENEX_STRIP
:command:`REPLACE <string(REGEX REPLACE)>`:
Match the regular expression as many times as possible and substitute
the replacement expression for the match for each element of the list
(same semantic as :command:`string(REGEX REPLACE)`).
.. code-block:: cmake
.. signature::
list(TRANSFORM <list> REPLACE <regular_expression>
<replace_expression> ...)
:target: TRANSFORM_REPLACE
``<SELECTOR>`` determines which elements of the list will be transformed.
Only one type of selector can be specified at a time.

View File

@@ -104,6 +104,17 @@ improved further like so:
VERBATIM
)
Finally, the above example can be expressed in a more simple and robust way
using an alternate generator expression:
.. code-block:: cmake
add_custom_target(run_some_tool
COMMAND some_tool "$<LIST:TRANSFORM,$<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>,PREPEND,-I>"
COMMAND_EXPAND_LISTS
VERBATIM
)
A common mistake is to try to split a generator expression across multiple
lines with indenting:
@@ -318,6 +329,15 @@ String Transformations
List Expressions
----------------
Most of the expressions in this section are closely associated with the
:command:`list` command, providing the same capabilities, but in
the form of a generator expression.
.. _GenEx List Comparisons:
List Comparisons
^^^^^^^^^^^^^^^^
.. genex:: $<IN_LIST:string,list>
.. versionadded:: 3.12
@@ -325,9 +345,186 @@ List Expressions
``1`` if ``string`` is an item in the semicolon-separated ``list``, else ``0``.
It uses case-sensitive comparisons.
.. genex:: $<JOIN:list,string>
.. _GenEx List Queries:
Joins the list with the content of ``string`` inserted between each item.
List Queries
^^^^^^^^^^^^
.. genex:: $<LIST:LENGTH,list>
.. versionadded:: 3.27
Returns the list's length.
.. genex:: $<LIST:GET,list,index,...>
.. versionadded:: 3.27
Returns the list of elements specified by indices from the list.
.. genex:: $<LIST:SUBLIST,list,begin,length>
.. versionadded:: 3.27
Returns a sublist of the given list. If <length> is 0, an empty list will be
returned. If <length> is -1 or the list is smaller than <begin>+<length> then
the remaining elements of the list starting at <begin> will be returned.
.. genex:: $<LIST:FIND,list,value>
.. versionadded:: 3.27
Returns the index of the element specified in the list or -1 if it wasn't
found.
.. _GenEx List Transformations:
List Transformations
^^^^^^^^^^^^^^^^^^^^
.. genex:: $<LIST:JOIN,list,glue>
.. versionadded:: 3.27
Returns a string which joins the list with the content of the ``glue`` string
inserted between each item.
.. genex:: $<LIST:APPEND,list,element,...>
.. versionadded:: 3.27
Returns a list with the elements appended.
.. genex:: $<LIST:PREPEND,list,element,...>
.. versionadded:: 3.27
Returns a list with the elements inserted at the beginning of the list.
.. genex:: $<LIST:INSERT,list,index,element,...>
.. versionadded:: 3.27
Returns a list with the elements inserted at the specified index. It is an
error to specify an out-of-range index. Valid indexes are 0 to N where N is
the length of the list, inclusive. An empty list has length 0.
.. genex:: $<LIST:POP_BACK,list>
.. versionadded:: 3.27
Returns a list with the last element was removed.
.. genex:: $<LIST:POP_FRONT,list>
.. versionadded:: 3.27
Returns a list with the first element was removed.
.. genex:: $<LIST:REMOVE_ITEM,list,value,...>
.. versionadded:: 3.27
Returns a list with all instances of the given values were removed.
.. genex:: $<LIST:REMOVE_AT,list,index,...>
.. versionadded:: 3.27
Returns a list with all values at given indices were removed.
.. genex:: $<LIST:REMOVE_DUPLICATES,list>
.. versionadded:: 3.27
Returns a list where duplicated items were removed. The relative order of
items is preserved, but if duplicates are encountered, only the first
instance is preserved.
.. genex:: $<LIST:FILTER,list,INCLUDE|EXCLUDE,regex>
.. versionadded:: 3.27
Returns a list with the items that match the regular expression ``regex``
were included or removed.
.. genex:: $<LIST:TRANSFORM,list,ACTION[,SELECTOR]>
.. versionadded:: 3.27
Returns the list transformed by applying an ``ACTION`` to all or, by
specifying a ``SELECTOR``, to the selected elements of the list.
.. note::
The ``TRANSFORM`` sub-command does not change the number of elements in the
list. If a ``SELECTOR`` is specified, only some elements will be changed,
the other ones will remain the same as before the transformation.
``ACTION`` specifies the action to apply to the elements of the list.
The actions have exactly the same semantics as of the
:command:`list(TRANSFORM)` command. ``ACTION`` must be one of the following:
:command:`APPEND <list(TRANSFORM_APPEND)>`, :command:`PREPEND <list(TRANSFORM_APPEND)>`
Append, prepend specified value to each element of the list.
.. code-block:: cmake
$<LIST:TRANSFORM,list,(APPEND|PREPEND),value[,SELECTOR]>
:command:`TOLOWER <list(TRANSFORM_TOLOWER)>`, :command:`TOUPPER <list(TRANSFORM_TOLOWER)>`
Convert each element of the list to lower, upper characters.
.. code-block:: cmake
$<LIST:TRANSFORM,list,(TOLOWER|TOUPPER)[,SELECTOR]>
:command:`STRIP <list(TRANSFORM_STRIP)>`
Remove leading and trailing spaces from each element of the list.
.. code-block:: cmake
$<LIST:TRANSFORM,list,STRIP[,SELECTOR]>
:command:`REPLACE <list(TRANSFORM_REPLACE)>`:
Match the regular expression as many times as possible and substitute
the replacement expression for the match for each element of the list.
.. code-block:: cmake
$<LIST:TRANSFORM,list,REPLACE,regular_expression,replace_expression[,SELECTOR]>
``SELECTOR`` determines which elements of the list will be transformed.
Only one type of selector can be specified at a time. When given,
``SELECTOR`` must be one of the following:
``AT``
Specify a list of indexes.
.. code-block:: cmake
$<LIST:TRANSFORM,list,ACTION,AT,index[,index...]>
``FOR``
Specify a range with, optionally, an increment used to iterate over the
range.
.. code-block:: cmake
$<LIST:TRANSFORM,list,ACTION,FOR,start,stop[,step]>
``REGEX``
Specify a regular expression.
Only elements matching the regular expression will be transformed.
.. code-block:: cmake
$<LIST:TRANSFORM,list,ACTION,REGEX,regular_expression>
.. genex:: $<JOIN:list,glue>
Joins the list with the content of the ``glue`` string inserted between each
item.
.. genex:: $<REMOVE_DUPLICATES:list>
@@ -344,6 +541,69 @@ List Expressions
Includes or removes items from ``list`` that match the regular expression
``regex``.
.. _GenEx List Ordering:
List Ordering
^^^^^^^^^^^^^
.. genex:: $<LIST:REVERSE,list>
.. versionadded:: 3.27
Returns the list with the elements in reverse order.
.. genex:: $<LIST:SORT,list[,(COMPARE:option|CASE:option|ORDER:option)]...>
.. versionadded:: 3.27
Returns the list sorted according the specified options.
Use one of the ``COMPARE`` options to select the comparison method
for sorting:
``STRING``
Sorts a list of strings alphabetically.
This is the default behavior if the ``COMPARE`` option is not given.
``FILE_BASENAME``
Sorts a list of pathnames of files by their basenames.
``NATURAL``
Sorts a list of strings using natural order
(see ``strverscmp(3)`` manual), i.e. such that contiguous digits
are compared as whole numbers.
For example: the following list `10.0 1.1 2.1 8.0 2.0 3.1`
will be sorted as `1.1 2.0 2.1 3.1 8.0 10.0` if the ``NATURAL``
comparison is selected where it will be sorted as
`1.1 10.0 2.0 2.1 3.1 8.0` with the ``STRING`` comparison.
Use one of the ``CASE`` options to select a case sensitive or case
insensitive sort mode:
``SENSITIVE``
List items are sorted in a case-sensitive manner.
This is the default behavior if the ``CASE`` option is not given.
``INSENSITIVE``
List items are sorted case insensitively. The order of
items which differ only by upper/lowercase is not specified.
To control the sort order, one of the ``ORDER`` options can be given:
``ASCENDING``
Sorts the list in ascending order.
This is the default behavior when the ``ORDER`` option is not given.
``DESCENDING``
Sorts the list in descending order.
This is an error to specify multiple times the same option. Various options
can be specified in any order:
.. code-block:: cmake
$<LIST:SORT,list,CASE:SENSITIVE,COMPARE:STRING,ORDER:DESCENDING>
Path Expressions
----------------

View File

@@ -0,0 +1,4 @@
GenEx-LIST
----------
* The :genex:`LIST` generator expression was added to manage lists.

View File

@@ -635,22 +635,48 @@ public:
using Arguments = Range<std::vector<std::string>>;
bool CheckPathParametersEx(cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
cm::string_view option, std::size_t count,
int required = 1, bool exactly = true)
bool CheckGenExParameters(cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
cm::string_view genex, cm::string_view option,
std::size_t count, int required = 1,
bool exactly = true)
{
if (static_cast<int>(count) < required ||
(exactly && static_cast<int>(count) > required)) {
std::string nbParameters;
switch (required) {
case 1:
nbParameters = "one parameter";
break;
case 2:
nbParameters = "two parameters";
break;
case 3:
nbParameters = "three parameters";
break;
case 4:
nbParameters = "four parameters";
break;
default:
nbParameters = cmStrCat(std::to_string(required), " parameters");
}
reportError(ctx, cnt->GetOriginalExpression(),
cmStrCat("$<PATH:", option, "> expression requires ",
(exactly ? "exactly" : "at least"), ' ',
(required == 1 ? "one parameter" : "two parameters"),
cmStrCat("$<", genex, ':', option, "> expression requires ",
(exactly ? "exactly" : "at least"), ' ', nbParameters,
'.'));
return false;
}
return true;
};
bool CheckPathParametersEx(cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
cm::string_view option, std::size_t count,
int required = 1, bool exactly = true)
{
return CheckGenExParameters(ctx, cnt, "PATH"_s, option, count, required,
exactly);
}
bool CheckPathParameters(cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
cm::string_view option, const Arguments& args,
@@ -658,6 +684,7 @@ bool CheckPathParameters(cmGeneratorExpressionContext* ctx,
{
return CheckPathParametersEx(ctx, cnt, option, args.size(), required);
};
std::string ToString(bool isTrue)
{
return isTrue ? "1" : "0";
@@ -1108,6 +1135,670 @@ static const struct PathEqualNode : public cmGeneratorExpressionNode
}
} pathEqualNode;
namespace {
inline bool CheckListParametersEx(cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
cm::string_view option, std::size_t count,
int required = 1, bool exactly = true)
{
return CheckGenExParameters(ctx, cnt, "LIST"_s, option, count, required,
exactly);
}
inline bool CheckListParameters(cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
cm::string_view option, const Arguments& args,
int required = 1)
{
return CheckListParametersEx(ctx, cnt, option, args.size(), required);
};
inline cmList GetList(std::string const& list)
{
return list.empty() ? cmList{} : cmList{ list, cmList::EmptyElements::Yes };
}
bool GetNumericArgument(const std::string& arg, int& value)
{
try {
std::size_t pos;
value = std::stoi(arg, &pos);
if (pos != arg.length()) {
// this is not a number
return false;
}
} catch (const std::invalid_argument&) {
return false;
}
return true;
}
bool GetNumericArguments(
cmGeneratorExpressionContext* ctx, const GeneratorExpressionContent* cnt,
Arguments const& args, std::vector<int>& indexes,
cmList::ExpandElements expandElements = cmList::ExpandElements::No)
{
using IndexRange = cmRange<Arguments::const_iterator>;
IndexRange arguments(args.begin(), args.end());
cmList list;
if (expandElements == cmList::ExpandElements::Yes) {
list = cmList{ args.begin(), args.end(), expandElements };
arguments = IndexRange{ list.begin(), list.end() };
}
for (auto const& value : arguments) {
int index;
if (!GetNumericArgument(value, index)) {
reportError(ctx, cnt->GetOriginalExpression(),
cmStrCat("index: \"", value, "\" is not a valid index"));
return false;
}
indexes.push_back(index);
}
return true;
}
}
static const struct ListNode : public cmGeneratorExpressionNode
{
ListNode() {} // NOLINT(modernize-use-equals-default)
int NumExpectedParameters() const override { return TwoOrMoreParameters; }
bool AcceptsArbitraryContentParameter() const override { return true; }
std::string Evaluate(
const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
static std::unordered_map<
cm::string_view,
std::function<std::string(cmGeneratorExpressionContext*,
const GeneratorExpressionContent*,
Arguments&)>>
listCommands{
{ "LENGTH"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParameters(ctx, cnt, "LENGTH"_s, args)) {
return std::to_string(GetList(args.front()).size());
}
return std::string{};
} },
{ "GET"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParametersEx(ctx, cnt, "GET"_s, args.size(), 2,
false)) {
auto list = GetList(args.front());
if (list.empty()) {
reportError(ctx, cnt->GetOriginalExpression(),
"given empty list");
return std::string{};
}
std::vector<int> indexes;
if (!GetNumericArguments(ctx, cnt, args.advance(1), indexes,
cmList::ExpandElements::Yes)) {
return std::string{};
}
try {
return list.get_items(indexes.begin(), indexes.end())
.to_string();
} catch (std::out_of_range& e) {
reportError(ctx, cnt->GetOriginalExpression(), e.what());
return std::string{};
}
}
return std::string{};
} },
{ "JOIN"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParameters(ctx, cnt, "JOIN"_s, args, 2)) {
return GetList(args.front()).join(args[1]);
}
return std::string{};
} },
{ "SUBLIST"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParameters(ctx, cnt, "SUBLIST"_s, args, 3)) {
auto list = GetList(args.front());
if (!list.empty()) {
std::vector<int> indexes;
if (!GetNumericArguments(ctx, cnt, args.advance(1), indexes)) {
return std::string{};
}
if (indexes[0] < 0) {
reportError(ctx, cnt->GetOriginalExpression(),
cmStrCat("begin index: ", indexes[0],
" is out of range 0 - ",
list.size() - 1));
return std::string{};
}
if (indexes[1] < -1) {
reportError(ctx, cnt->GetOriginalExpression(),
cmStrCat("length: ", indexes[1],
" should be -1 or greater"));
return std::string{};
}
try {
return list
.sublist(static_cast<cmList::size_type>(indexes[0]),
static_cast<cmList::size_type>(indexes[1]))
.to_string();
} catch (std::out_of_range& e) {
reportError(ctx, cnt->GetOriginalExpression(), e.what());
return std::string{};
}
}
}
return std::string{};
} },
{ "FIND"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParameters(ctx, cnt, "FIND"_s, args, 2)) {
auto list = GetList(args.front());
auto index = list.find(args[1]);
return index == cmList::npos ? "-1" : std::to_string(index);
}
return std::string{};
} },
{ "APPEND"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParametersEx(ctx, cnt, "APPEND"_s, args.size(), 2,
false)) {
auto list = args.front();
args.advance(1);
return cmList::append(args.begin(), args.end(), list);
}
return std::string{};
} },
{ "PREPEND"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParametersEx(ctx, cnt, "PREPEND"_s, args.size(), 2,
false)) {
auto list = args.front();
args.advance(1);
return cmList::prepend(args.begin(), args.end(), list);
}
return std::string{};
} },
{ "INSERT"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParametersEx(ctx, cnt, "INSERT"_s, args.size(), 3,
false)) {
int index;
if (!GetNumericArgument(args[1], index)) {
reportError(
ctx, cnt->GetOriginalExpression(),
cmStrCat("index: \"", args[1], "\" is not a valid index"));
return std::string{};
}
try {
auto list = GetList(args.front());
args.advance(2);
list.insert_items(index, args.begin(), args.end());
return list.to_string();
} catch (std::out_of_range& e) {
reportError(ctx, cnt->GetOriginalExpression(), e.what());
return std::string{};
}
}
return std::string{};
} },
{ "POP_BACK"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParameters(ctx, cnt, "POP_BACK"_s, args)) {
auto list = GetList(args.front());
if (!list.empty()) {
list.pop_back();
return list.to_string();
}
}
return std::string{};
} },
{ "POP_FRONT"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParameters(ctx, cnt, "POP_FRONT"_s, args)) {
auto list = GetList(args.front());
if (!list.empty()) {
list.pop_front();
return list.to_string();
}
}
return std::string{};
} },
{ "REMOVE_DUPLICATES"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParameters(ctx, cnt, "REMOVE_DUPLICATES"_s, args)) {
return GetList(args.front()).remove_duplicates().to_string();
}
return std::string{};
} },
{ "REMOVE_ITEM"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParametersEx(ctx, cnt, "REMOVE_ITEM"_s, args.size(),
2, false)) {
auto list = GetList(args.front());
args.advance(1);
cmList items{ args.begin(), args.end(),
cmList::ExpandElements::Yes };
return list.remove_items(items.begin(), items.end()).to_string();
}
return std::string{};
} },
{ "REMOVE_AT"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParametersEx(ctx, cnt, "REMOVE_AT"_s, args.size(), 2,
false)) {
auto list = GetList(args.front());
std::vector<int> indexes;
if (!GetNumericArguments(ctx, cnt, args.advance(1), indexes,
cmList::ExpandElements::Yes)) {
return std::string{};
}
try {
return list.remove_items(indexes.begin(), indexes.end())
.to_string();
} catch (std::out_of_range& e) {
reportError(ctx, cnt->GetOriginalExpression(), e.what());
return std::string{};
}
}
return std::string{};
} },
{ "FILTER"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParameters(ctx, cnt, "FILTER"_s, args, 3)) {
auto const& op = args[1];
if (op != "INCLUDE"_s && op != "EXCLUDE"_s) {
reportError(
ctx, cnt->GetOriginalExpression(),
cmStrCat("sub-command FILTER does not recognize operator \"",
op, "\". It must be either INCLUDE or EXCLUDE."));
return std::string{};
}
try {
return GetList(args.front())
.filter(args[2],
op == "INCLUDE"_s ? cmList::FilterMode::INCLUDE
: cmList::FilterMode::EXCLUDE)
.to_string();
} catch (std::invalid_argument&) {
reportError(
ctx, cnt->GetOriginalExpression(),
cmStrCat("sub-command FILTER, failed to compile regex \"",
args[2], "\"."));
return std::string{};
}
}
return std::string{};
} },
{ "TRANSFORM"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParametersEx(ctx, cnt, "TRANSFORM"_s, args.size(), 2,
false)) {
auto list = GetList(args.front());
if (!list.empty()) {
struct ActionDescriptor
{
ActionDescriptor(std::string name)
: Name(std::move(name))
{
}
ActionDescriptor(std::string name,
cmList::TransformAction action, int arity)
: Name(std::move(name))
, Action(action)
, Arity(arity)
{
}
operator const std::string&() const { return this->Name; }
std::string Name;
cmList::TransformAction Action;
int Arity = 0;
};
static std::set<
ActionDescriptor,
std::function<bool(const std::string&, const std::string&)>>
descriptors{
{ { "APPEND", cmList::TransformAction::APPEND, 1 },
{ "PREPEND", cmList::TransformAction::PREPEND, 1 },
{ "TOUPPER", cmList::TransformAction::TOUPPER, 0 },
{ "TOLOWER", cmList::TransformAction::TOLOWER, 0 },
{ "STRIP", cmList::TransformAction::STRIP, 0 },
{ "REPLACE", cmList::TransformAction::REPLACE, 2 } },
[](const std::string& x, const std::string& y) {
return x < y;
}
};
auto descriptor = descriptors.find(args.advance(1).front());
if (descriptor == descriptors.end()) {
reportError(ctx, cnt->GetOriginalExpression(),
cmStrCat(" sub-command TRANSFORM, ",
args.front(), " invalid action."));
return std::string{};
}
// Action arguments
args.advance(1);
if (args.size() < descriptor->Arity) {
reportError(ctx, cnt->GetOriginalExpression(),
cmStrCat("sub-command TRANSFORM, action ",
descriptor->Name, " expects ",
descriptor->Arity, " argument(s)."));
return std::string{};
}
std::vector<std::string> arguments;
if (descriptor->Arity > 0) {
arguments = std::vector<std::string>(
args.begin(), args.begin() + descriptor->Arity);
args.advance(descriptor->Arity);
}
const std::string REGEX{ "REGEX" };
const std::string AT{ "AT" };
const std::string FOR{ "FOR" };
std::unique_ptr<cmList::TransformSelector> selector;
try {
// handle optional arguments
while (!args.empty()) {
if ((args.front() == REGEX || args.front() == AT ||
args.front() == FOR) &&
selector) {
reportError(ctx, cnt->GetOriginalExpression(),
cmStrCat("sub-command TRANSFORM, selector "
"already specified (",
selector->GetTag(), ")."));
return std::string{};
}
// REGEX selector
if (args.front() == REGEX) {
if (args.advance(1).empty()) {
reportError(
ctx, cnt->GetOriginalExpression(),
"sub-command TRANSFORM, selector REGEX expects "
"'regular expression' argument.");
return std::string{};
}
selector = cmList::TransformSelector::New<
cmList::TransformSelector::REGEX>(args.front());
args.advance(1);
continue;
}
// AT selector
if (args.front() == AT) {
args.advance(1);
// get all specified indexes
std::vector<cmList::index_type> indexes;
while (!args.empty()) {
cmList indexList{ args.front() };
for (auto const& index : indexList) {
int value;
if (!GetNumericArgument(index, value)) {
// this is not a number, stop processing
reportError(
ctx, cnt->GetOriginalExpression(),
cmStrCat("sub-command TRANSFORM, selector AT: '",
index, "': unexpected argument."));
return std::string{};
}
indexes.push_back(value);
}
args.advance(1);
}
if (indexes.empty()) {
reportError(ctx, cnt->GetOriginalExpression(),
"sub-command TRANSFORM, selector AT "
"expects at least one "
"numeric value.");
return std::string{};
}
selector = cmList::TransformSelector::New<
cmList::TransformSelector::AT>(std::move(indexes));
continue;
}
// FOR selector
if (args.front() == FOR) {
if (args.advance(1).size() < 2) {
reportError(ctx, cnt->GetOriginalExpression(),
"sub-command TRANSFORM, selector FOR "
"expects, at least,"
" two arguments.");
return std::string{};
}
cmList::index_type start = 0;
cmList::index_type stop = 0;
cmList::index_type step = 1;
bool valid = false;
if (GetNumericArgument(args.front(), start) &&
GetNumericArgument(args.advance(1).front(), stop)) {
valid = true;
}
if (!valid) {
reportError(
ctx, cnt->GetOriginalExpression(),
"sub-command TRANSFORM, selector FOR expects, "
"at least, two numeric values.");
return std::string{};
}
// try to read a third numeric value for step
if (!args.advance(1).empty()) {
if (!GetNumericArgument(args.front(), step)) {
// this is not a number
step = -1;
}
args.advance(1);
}
if (step <= 0) {
reportError(
ctx, cnt->GetOriginalExpression(),
"sub-command TRANSFORM, selector FOR expects "
"positive numeric value for <step>.");
return std::string{};
}
selector = cmList::TransformSelector::New<
cmList::TransformSelector::FOR>({ start, stop, step });
continue;
}
reportError(ctx, cnt->GetOriginalExpression(),
cmStrCat("sub-command TRANSFORM, '",
cmJoin(args, ", "),
"': unexpected argument(s)."));
return std::string{};
}
return list
.transform(descriptor->Action, arguments,
std::move(selector))
.to_string();
} catch (cmList::transform_error& e) {
reportError(ctx, cnt->GetOriginalExpression(), e.what());
return std::string{};
}
}
}
return std::string{};
} },
{ "REVERSE"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParameters(ctx, cnt, "REVERSE"_s, args)) {
return GetList(args.front()).reverse().to_string();
}
return std::string{};
} },
{ "SORT"_s,
[](cmGeneratorExpressionContext* ctx,
const GeneratorExpressionContent* cnt,
Arguments& args) -> std::string {
if (CheckListParametersEx(ctx, cnt, "SORT"_s, args.size(), 1,
false)) {
auto list = GetList(args.front());
args.advance(1);
const auto COMPARE = "COMPARE:"_s;
const auto CASE = "CASE:"_s;
const auto ORDER = "ORDER:"_s;
using SortConfig = cmList::SortConfiguration;
SortConfig sortConfig;
for (auto const& arg : args) {
if (cmHasPrefix(arg, COMPARE)) {
if (sortConfig.Compare !=
SortConfig::CompareMethod::DEFAULT) {
reportError(ctx, cnt->GetOriginalExpression(),
"sub-command SORT, COMPARE option has been "
"specified multiple times.");
return std::string{};
}
auto option =
cm::string_view{ arg.c_str() + COMPARE.length() };
if (option == "STRING"_s) {
sortConfig.Compare = SortConfig::CompareMethod::STRING;
continue;
}
if (option == "FILE_BASENAME"_s) {
sortConfig.Compare =
SortConfig::CompareMethod::FILE_BASENAME;
continue;
}
if (option == "NATURAL"_s) {
sortConfig.Compare = SortConfig::CompareMethod::NATURAL;
continue;
}
reportError(
ctx, cnt->GetOriginalExpression(),
cmStrCat(
"sub-command SORT, an invalid COMPARE option has been "
"specified: \"",
option, "\"."));
return std::string{};
}
if (cmHasPrefix(arg, CASE)) {
if (sortConfig.Case !=
SortConfig::CaseSensitivity::DEFAULT) {
reportError(ctx, cnt->GetOriginalExpression(),
"sub-command SORT, CASE option has been "
"specified multiple times.");
return std::string{};
}
auto option = cm::string_view{ arg.c_str() + CASE.length() };
if (option == "SENSITIVE"_s) {
sortConfig.Case = SortConfig::CaseSensitivity::SENSITIVE;
continue;
}
if (option == "INSENSITIVE"_s) {
sortConfig.Case = SortConfig::CaseSensitivity::INSENSITIVE;
continue;
}
reportError(
ctx, cnt->GetOriginalExpression(),
cmStrCat(
"sub-command SORT, an invalid CASE option has been "
"specified: \"",
option, "\"."));
return std::string{};
}
if (cmHasPrefix(arg, ORDER)) {
if (sortConfig.Order != SortConfig::OrderMode::DEFAULT) {
reportError(ctx, cnt->GetOriginalExpression(),
"sub-command SORT, ORDER option has been "
"specified multiple times.");
return std::string{};
}
auto option =
cm::string_view{ arg.c_str() + ORDER.length() };
if (option == "ASCENDING"_s) {
sortConfig.Order = SortConfig::OrderMode::ASCENDING;
continue;
}
if (option == "DESCENDING"_s) {
sortConfig.Order = SortConfig::OrderMode::DESCENDING;
continue;
}
reportError(
ctx, cnt->GetOriginalExpression(),
cmStrCat(
"sub-command SORT, an invalid ORDER option has been "
"specified: \"",
option, "\"."));
return std::string{};
}
reportError(ctx, cnt->GetOriginalExpression(),
cmStrCat("sub-command SORT, option \"", arg,
"\" is invalid."));
return std::string{};
}
return list.sort(sortConfig).to_string();
}
return std::string{};
} }
};
if (cm::contains(listCommands, parameters.front())) {
auto args = Arguments{ parameters }.advance(1);
return listCommands[parameters.front()](context, content, args);
}
reportError(context, content->GetOriginalExpression(),
cmStrCat(parameters.front(), ": invalid option."));
return std::string{};
}
} listNode;
static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
{
MakeCIdentifierNode() {} // NOLINT(modernize-use-equals-default)
@@ -1559,7 +2250,8 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
// reportError(context, content->GetOriginalExpression(), "");
reportError(
context, content->GetOriginalExpression(),
"$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets "
"$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary "
"targets "
"to specify include directories, compile definitions, and compile "
"options. It may not be used with the add_custom_command, "
"add_custom_target, or file(GENERATE) commands.");
@@ -1704,7 +2396,8 @@ static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode
reportError(
context, content->GetOriginalExpression(),
"$<LINK_LANG_AND_ID:lang,id> may only be used with binary targets "
"to specify link libraries, link directories, link options, and link "
"to specify link libraries, link directories, link options, and "
"link "
"depends.");
return std::string();
}
@@ -2086,7 +2779,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
reportError(
context, content->GetOriginalExpression(),
"$<TARGET_PROPERTY:prop> may only be used with binary targets. "
"It may not be used with add_custom_command or add_custom_target. "
"It may not be used with add_custom_command or add_custom_target. "
" "
" "
"Specify the target to read a property from using the "
"$<TARGET_PROPERTY:tgt,prop> signature instead.");
@@ -3780,6 +4474,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
{ "IN_LIST", &inListNode },
{ "FILTER", &filterNode },
{ "REMOVE_DUPLICATES", &removeDuplicatesNode },
{ "LIST", &listNode },
{ "LOWER_CASE", &lowerCaseNode },
{ "UPPER_CASE", &upperCaseNode },
{ "PATH", &pathNode },

View File

@@ -835,18 +835,19 @@ cmList::size_type cmList::ComputeIndex(index_type pos, bool boundCheck) const
cmStrCat("index: ", pos, " out of range (0, 0)"));
}
auto index = pos;
if (!this->Values.empty()) {
auto length = this->Values.size();
if (pos < 0) {
pos = static_cast<index_type>(length) + pos;
if (index < 0) {
index = static_cast<index_type>(length) + index;
}
if (pos < 0 || length <= static_cast<size_type>(pos)) {
if (index < 0 || length <= static_cast<size_type>(index)) {
throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
this->Values.size(), ", ",
this->Values.size() - 1, ")"));
}
}
return pos;
return index;
}
return pos < 0 ? this->Values.size() + pos : pos;
@@ -860,18 +861,19 @@ cmList::size_type cmList::ComputeInsertIndex(index_type pos,
cmStrCat("index: ", pos, " out of range (0, 0)"));
}
auto index = pos;
if (!this->Values.empty()) {
auto length = this->Values.size();
if (pos < 0) {
pos = static_cast<index_type>(length) + pos;
if (index < 0) {
index = static_cast<index_type>(length) + index;
}
if (pos < 0 || length < static_cast<size_type>(pos)) {
if (index < 0 || length < static_cast<size_type>(index)) {
throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
this->Values.size(), ", ",
this->Values.size(), ")"));
}
}
return pos;
return index;
}
return pos < 0 ? this->Values.size() + pos : pos;

View File

@@ -1,5 +1,5 @@
CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
list index: (-2147483643|2147483647) out of range \(-5, 4\)
list index: (-2147483648|2147483647) out of range \(-5, 4\)
Call Stack \(most recent call first\):
CMP0121-ERANGE-OLD.cmake:2 \(include\)
CMakeLists.txt:3 \(include\)

View File

@@ -9,7 +9,7 @@ Call Stack \(most recent call first\):
This warning is for project developers. Use -Wno-dev to suppress it.
.*
CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
list index: (-2147483643|2147483647) out of range \(-5, 4\)
list index: (-2147483648|2147483647) out of range \(-5, 4\)
Call Stack \(most recent call first\):
CMP0121-ERANGE-WARN.cmake:2 \(include\)
CMakeLists.txt:3 \(include\)

View File

@@ -370,6 +370,7 @@ add_RunCMake_test(GenEx-TARGET_PROPERTY)
add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
add_RunCMake_test(GenEx-PATH)
add_RunCMake_test(GenEx-PATH_EQUAL)
add_RunCMake_test(GenEx-LIST)
add_RunCMake_test(GeneratorExpression)
add_RunCMake_test(GeneratorInstance)
add_RunCMake_test(GeneratorPlatform)

View File

@@ -0,0 +1,34 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(APPEND listvar e)
set (output "$<LIST:APPEND,a;b;c;d,e>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(APPEND listvar e f)
set (output "$<LIST:APPEND,a;b;c;d,e,f>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(APPEND listvar e f)
set (output "$<LIST:APPEND,a;b;c;d,e;f>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
unset(listvar)
list(APPEND listvar e f)
set (output "$<LIST:APPEND,,e,f>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:APPEND..." ${errors})

View File

@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.18...3.25)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,9 @@
CMake Error at FILTER-wrong-operator.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:FILTER,a;b;c,WRONG_OPERATOR,\^a>
sub-command FILTER does not recognize operator "WRONG_OPERATOR". It must
be either INCLUDE or EXCLUDE.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:FILTER,a;b;c,WRONG_OPERATOR,^a>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at FILTER-wrong-regex.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:FILTER,a;b;c,INCLUDE,\^\(a>
sub-command FILTER, failed to compile regex "\^\(a".
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:FILTER,a;b;c,INCLUDE,^(a>")

View File

@@ -0,0 +1,20 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(FIND listvar "c" reference)
set (output "$<LIST:FIND,a;b;c;d,c>")
if (NOT output EQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(FIND listvar "e" reference)
set (output "$<LIST:FIND,a;b;c;d,e>")
if (NOT output EQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:FIND..." ${errors})

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at GET-wrong-index1.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:GET,,0>
given empty list
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:GET,,0>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at GET-wrong-index2.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:GET,a;b,2>
index: 2 out of range \(-2, 1\)
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:GET,a;b,2>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at GET-wrong-index3.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:GET,a;b,1,-3>
index: -3 out of range \(-2, 1\)
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:GET,a;b,1,-3>")

View File

@@ -0,0 +1,20 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(GET listvar 0 2 reference)
set (output "$<LIST:GET,a;b;c;d,0,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(GET listvar 0 -3 2 reference)
set (output "$<LIST:GET,a;b;c;d,0,-3,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:GET..." ${errors})

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at INSERT-wrong-index1.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:INSERT,a;b;c,4,d>
index: 4 out of range \(-3, 3\)
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:INSERT,a;b;c,4,d>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at INSERT-wrong-index2.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:INSERT,a;b;c,-4,d>
index: -4 out of range \(-3, 3\)
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:INSERT,a;b;c,-4,d>")

View File

@@ -0,0 +1,50 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(INSERT listvar 1 e)
set (output "$<LIST:INSERT,a;b;c;d,1,e>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(INSERT listvar 2 e f)
set (output "$<LIST:INSERT,a;b;c;d,2,e,f>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(INSERT listvar 0 e f)
set (output "$<LIST:INSERT,a;b;c;d,0,e;f>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(INSERT listvar -2 e f)
set (output "$<LIST:INSERT,a;b;c;d,-2,e;f>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(INSERT listvar 3 e f)
set (output "$<LIST:INSERT,a;b;c;d,3,e;f>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
unset(listvar)
list(INSERT listvar 0 e f)
set (output "$<LIST:INSERT,,0,e,f>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:INSERT..." ${errors})

View File

@@ -0,0 +1,35 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(JOIN listvar ":" reference)
set (output "$<LIST:JOIN,a;b;c;d,:>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(JOIN listvar "" reference)
set (output "$<LIST:JOIN,a;b;c;d,>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a)
list(JOIN listvar ":" reference)
set (output "$<LIST:JOIN,a,:>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
unset(listvar)
list(JOIN listvar ":" reference)
set (output "$<LIST:JOIN,,:>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:JOIN..." ${errors})

View File

@@ -0,0 +1,30 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(LENGTH listvar reference)
set (output "$<LIST:LENGTH,a;b;c;d>")
if (NOT output EQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar "")
list(LENGTH listvar reference)
set (output "$<LIST:LENGTH,>")
if (NOT output EQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
unset(listvar)
list(LENGTH listvar reference)
set (output "$<LIST:LENGTH,>")
if (NOT output EQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:LENGTH..." ${errors})

View File

@@ -0,0 +1,18 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(POP_BACK listvar)
set (output "$<LIST:POP_BACK,a;b;c;d>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set (output "$<LIST:POP_BACK,>")
if (NOT output STREQUAL "")
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:POP_BACK..." ${errors})

View File

@@ -0,0 +1,18 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(POP_FRONT listvar)
set (output "$<LIST:POP_FRONT,a;b;c;d>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set (output "$<LIST:POP_FRONT,>")
if (NOT output STREQUAL "")
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:POP_FRONT..." ${errors})

View File

@@ -0,0 +1,34 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(PREPEND listvar e)
set (output "$<LIST:PREPEND,a;b;c;d,e>")
if (NOT output STREQUAL listvar)
list (PREPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(PREPEND listvar e f)
set (output "$<LIST:PREPEND,a;b;c;d,e,f>")
if (NOT output STREQUAL listvar)
list (PREPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(PREPEND listvar e f)
set (output "$<LIST:PREPEND,a;b;c;d,e;f>")
if (NOT output STREQUAL listvar)
list (PREPEND errors "returns bad value: ${output}")
endif()
unset(listvar)
list(PREPEND listvar e f)
set (output "$<LIST:PREPEND,,e,f>")
if (NOT output STREQUAL listvar)
list (PREPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:PREPEND..." ${errors})

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at REMOVE_AT-wrong-index1.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:REMOVE_AT,,0>
index: 0 out of range \(0, 0\)
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:REMOVE_AT,,0>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at REMOVE_AT-wrong-index2.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:REMOVE_AT,a;b;c,3>
index: 3 out of range \(-3, 2\)
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:REMOVE_AT,a;b;c,3>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at REMOVE_AT-wrong-index3.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:REMOVE_AT,a;b;c,-4>
index: -4 out of range \(-3, 2\)
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:REMOVE_AT,a;b;c,-4>")

View File

@@ -0,0 +1,25 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(REMOVE_AT listvar 1 3)
set (output "$<LIST:REMOVE_AT,a;b;c;d,1,3>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(REMOVE_AT listvar 1 -2)
set (output "$<LIST:REMOVE_AT,a;b;c;d,1;-2>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set (output "$<LIST:REMOVE_AT,a;b;c;d,1,0,3;2>")
if (NOT output STREQUAL "")
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:REMOVE_AT..." ${errors})

View File

@@ -0,0 +1,20 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(REMOVE_DUPLICATES listvar)
set (output "$<LIST:REMOVE_DUPLICATES,a;b;c;d>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar "b;c;b;a;a;c;b;a;c;b")
list(REMOVE_DUPLICATES listvar)
set (output "$<LIST:REMOVE_DUPLICATES,b;c;b;a;a;c;b;a;c;b>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:REMOVE_DUPLICATES..." ${errors})

View File

@@ -0,0 +1,32 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(REMOVE_ITEM listvar b d)
set (output "$<LIST:REMOVE_ITEM,a;b;c;d,b,d>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(REMOVE_ITEM listvar b e)
set (output "$<LIST:REMOVE_ITEM,a;b;c;d,b,e>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar a b c d)
list(REMOVE_ITEM listvar b a d c)
set (output "$<LIST:REMOVE_ITEM,a;b;c;d,b;a;d;c>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set (output "$<LIST:REMOVE_ITEM,,b;a;d;c>")
if (NOT output STREQUAL "")
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:REMOVE_ITEM..." ${errors})

View File

@@ -0,0 +1,19 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(REVERSE listvar)
set (output "$<LIST:REVERSE,a;b;c;d>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set (output "$<LIST:REVERSE,>")
if (NOT output STREQUAL "")
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:REVERSE..." ${errors})

View File

@@ -0,0 +1,130 @@
include(RunCMake)
run_cmake(no-arguments)
run_cmake(bad-option)
function(check_list_syntax name test)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-${test}-build)
set(RunCMake_TEST_VARIANT_DESCRIPTION " - ${name}")
run_cmake_with_options(${test} ${ARGN})
endfunction()
## Unexpected arguments
### sub-commands with one argument
foreach (subcommand IN ITEMS LENGTH POP_BACK POP_FRONT REMOVE_DUPLICATES REVERSE)
check_list_syntax (${subcommand} unexpected-arg "-DLIST_ARGUMENTS=${subcommand},ARG1,ARG2")
endforeach()
### sub-commands with two arguments
foreach (subcommand IN ITEMS FIND JOIN)
check_list_syntax (${subcommand} unexpected-arg "-DLIST_ARGUMENTS=${subcommand},ARG1,ARG2,ARG3")
endforeach()
### sub-commands with three arguments
foreach (subcommand IN ITEMS SUBLIST FILTER)
check_list_syntax (${subcommand} unexpected-arg "-DLIST_ARGUMENTS=${subcommand},ARG1,ARG2,ARG3,ARG4")
endforeach()
# TRANSFORM sub-commands
set(RunCMake-stderr-file "TRANSFORM-unexpected-arg-stderr.txt")
foreach (action IN ITEMS TOLOWER TOUPPER STRIP)
check_list_syntax (TRANSFORM-${action} unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,${action},ARG2")
endforeach()
foreach (action IN ITEMS APPEND PREPEND)
check_list_syntax (TRANSFORM-${action} unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,${action},ARG2,ARG3")
endforeach()
foreach (action IN ITEMS REPLACE)
check_list_syntax (TRANSFORM-${action} unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,${action},ARG2,ARG3,ARG4")
endforeach()
check_list_syntax (TRANSFORM-SELECTOR-REGEX unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,STRIP,REGEX,ARG2,ARG3")
check_list_syntax (TRANSFORM-SELECTOR-FOR unexpected-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,STRIP,FOR,1,2,3,4")
unset(RunCMake-stderr-file)
## Missing arguments
### sub-command with, at least, two arguments
foreach (subcommand IN ITEMS GET APPEND PREPEND REMOVE_ITEM REMOVE_AT TRANSFORM)
check_list_syntax (${subcommand} missing-arg "-DLIST_ARGUMENTS=${subcommand},ARG1")
endforeach()
### sub-command with, at least, three arguments
foreach (subcommand IN ITEMS INSERT)
check_list_syntax (${subcommand} missing-arg "-DLIST_ARGUMENTS=${subcommand},ARG1,ARG2")
endforeach()
# TRANSFORM sub-commands
set(RunCMake-stderr-file "TRANSFORM-missing-arg-stderr.txt")
foreach (action IN ITEMS APPEND PREPEND)
check_list_syntax (TRANSFORM-${action} missing-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,${action}")
endforeach()
check_list_syntax (TRANSFORM-REPLACE-1 missing-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,REPLACE,ARG2")
check_list_syntax (TRANSFORM-REPLACE-2 missing-arg "-DLIST_ARGUMENTS=TRANSFORM,ARG1,REPLACE")
unset(RunCMake-stderr-file)
run_cmake(GET-wrong-index1)
run_cmake(GET-wrong-index2)
run_cmake(GET-wrong-index3)
run_cmake(SUBLIST-wrong-argument1)
run_cmake(SUBLIST-wrong-argument2)
run_cmake(INSERT-wrong-index1)
run_cmake(INSERT-wrong-index2)
run_cmake(REMOVE_AT-wrong-index1)
run_cmake(REMOVE_AT-wrong-index2)
run_cmake(REMOVE_AT-wrong-index3)
run_cmake(FILTER-wrong-operator)
run_cmake(FILTER-wrong-regex)
run_cmake(TRANSFORM-wrong-action)
run_cmake(TRANSFORM-REPLACE-wrong-regex)
run_cmake(TRANSFORM-REPLACE-invalid-replace1)
run_cmake(TRANSFORM-REPLACE-invalid-replace2)
run_cmake(TRANSFORM-selector-REGEX-no-arguments)
run_cmake(TRANSFORM-selector-REGEX-wrong-regex)
run_cmake(TRANSFORM-selector-AT-no-arguments)
run_cmake(TRANSFORM-selector-AT-wrong-argument)
run_cmake(TRANSFORM-selector-AT-wrong-index)
run_cmake(TRANSFORM-selector-FOR-no-arguments)
run_cmake(TRANSFORM-selector-FOR-missing-arguments)
run_cmake(TRANSFORM-selector-FOR-wrong-argument)
run_cmake(TRANSFORM-selector-FOR-wrong-index)
run_cmake(TRANSFORM-selector-FOR-zero-step)
run_cmake(TRANSFORM-selector-FOR-negative-step)
run_cmake(TRANSFORM-selector-FOR-backwards-range)
run_cmake(SORT-wrong-option)
run_cmake(SORT-wrong-COMPARE-option)
run_cmake(SORT-wrong-CASE-option)
run_cmake(SORT-wrong-ORDER-option)
run_cmake(SORT-duplicate-COMPARE-option)
run_cmake(SORT-duplicate-CASE-option)
run_cmake(SORT-duplicate-ORDER-option)
function(check_list_execution name)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
set(RunCMake_TEST_NO_CLEAN 1)
set(RunCMake_TEST_VARIANT_DESCRIPTION " - ${name}")
run_cmake_with_options(generate -DLIST_TEST=${name})
run_cmake_command(check "${CMAKE_COMMAND}" "-DRunCMake_SOURCE_DIR=${RunCMake_SOURCE_DIR}" -P "${RunCMake_TEST_BINARY_DIR}/${name}.cmake")
endfunction()
check_list_execution (LENGTH)
check_list_execution (GET)
check_list_execution (JOIN)
check_list_execution (SUBLIST)
check_list_execution (FIND)
check_list_execution (APPEND)
check_list_execution (PREPEND)
check_list_execution (INSERT)
check_list_execution (POP_BACK)
check_list_execution (POP_FRONT)
check_list_execution (REMOVE_ITEM)
check_list_execution (REMOVE_AT)
check_list_execution (REMOVE_DUPLICATES)
check_list_execution (TRANSFORM-TOUPPER)
check_list_execution (TRANSFORM-TOLOWER)
check_list_execution (TRANSFORM-STRIP)
check_list_execution (TRANSFORM-APPEND)
check_list_execution (TRANSFORM-PREPEND)
check_list_execution (TRANSFORM-REPLACE)
check_list_execution (REVERSE)
check_list_execution (SORT)

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at SORT-duplicate-CASE-option.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:SORT,a;b,COMPARE:STRING,CASE:SENSITIVE,CASE:SENSITIVE>
sub-command SORT, CASE option has been specified multiple times.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:STRING,CASE:SENSITIVE,CASE:SENSITIVE>")

View File

@@ -0,0 +1,8 @@
CMake Error at SORT-duplicate-COMPARE-option.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:SORT,a;b,COMPARE:STRING,COMPARE:NATURAL>
sub-command SORT, COMPARE option has been specified multiple times.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:STRING,COMPARE:NATURAL>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at SORT-duplicate-ORDER-option.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:SORT,a;b,ORDER:ASCENDING,COMPARE:STRING,ORDER:DESCENDING,CASE:SENSITIVE>
sub-command SORT, ORDER option has been specified multiple times.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,ORDER:ASCENDING,COMPARE:STRING,ORDER:DESCENDING,CASE:SENSITIVE>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,9 @@
CMake Error at SORT-wrong-CASE-option.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:SORT,a;b,COMPARE:STRING,CASE:WRONG_OPTION>
sub-command SORT, an invalid CASE option has been specified:
"WRONG_OPTION".
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:STRING,CASE:WRONG_OPTION>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,9 @@
CMake Error at SORT-wrong-COMPARE-option.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:SORT,a;b,COMPARE:WRONG_OPTION>
sub-command SORT, an invalid COMPARE option has been specified:
"WRONG_OPTION".
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:WRONG_OPTION>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,9 @@
CMake Error at SORT-wrong-ORDER-option.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:SORT,a;b,COMPARE:STRING,CASE:SENSITIVE,ORDER:WRONG_OPTION>
sub-command SORT, an invalid ORDER option has been specified:
"WRONG_OPTION".
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,COMPARE:STRING,CASE:SENSITIVE,ORDER:WRONG_OPTION>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at SORT-wrong-option.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:SORT,a;b,WRONG_OPTION>
sub-command SORT, option "WRONG_OPTION" is invalid.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SORT,a;b,WRONG_OPTION>")

View File

@@ -0,0 +1,92 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(source_unsorted c/B.h a/c.h B/a.h)
set(listvar ${source_unsorted})
list(SORT listvar)
set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar ${source_unsorted})
list(SORT listvar CASE INSENSITIVE ORDER ASCENDING COMPARE STRING)
set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:INSENSITIVE,ORDER:ASCENDING,COMPARE:STRING>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar ${source_unsorted})
list(SORT listvar CASE INSENSITIVE ORDER DESCENDING COMPARE STRING)
set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:INSENSITIVE,ORDER:DESCENDING,COMPARE:STRING>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar ${source_unsorted})
list(SORT listvar CASE SENSITIVE ORDER ASCENDING COMPARE STRING)
set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:SENSITIVE,ORDER:ASCENDING,COMPARE:STRING>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar ${source_unsorted})
list(SORT listvar CASE SENSITIVE ORDER DESCENDING COMPARE STRING)
set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:SENSITIVE,ORDER:DESCENDING,COMPARE:STRING>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar ${source_unsorted})
list(SORT listvar CASE INSENSITIVE ORDER ASCENDING COMPARE FILE_BASENAME)
set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:INSENSITIVE,ORDER:ASCENDING,COMPARE:FILE_BASENAME>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar ${source_unsorted})
list(SORT listvar CASE INSENSITIVE ORDER DESCENDING COMPARE FILE_BASENAME)
set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:INSENSITIVE,ORDER:DESCENDING,COMPARE:FILE_BASENAME>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar ${source_unsorted})
list(SORT listvar CASE SENSITIVE ORDER ASCENDING COMPARE FILE_BASENAME)
set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:SENSITIVE,ORDER:ASCENDING,COMPARE:FILE_BASENAME>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar ${source_unsorted})
list(SORT listvar CASE SENSITIVE ORDER DESCENDING COMPARE FILE_BASENAME)
set (output "$<LIST:SORT,c/B.h;a/c.h;B/a.h,CASE:SENSITIVE,ORDER:DESCENDING,COMPARE:FILE_BASENAME>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar 10.0 1.1 2.1 8.0 2.0 3.1)
list(SORT listvar CASE SENSITIVE ORDER DESCENDING COMPARE STRING)
set (output "$<LIST:SORT,10.0;1.1;2.1;8.0;2.0;3.1,CASE:SENSITIVE,ORDER:DESCENDING,COMPARE:STRING>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar 10.0 1.1 2.1 8.0 2.0 3.1)
list(SORT listvar CASE SENSITIVE ORDER DESCENDING COMPARE NATURAL)
set (output "$<LIST:SORT,10.0;1.1;2.1;8.0;2.0;3.1,CASE:SENSITIVE,ORDER:DESCENDING,COMPARE:NATURAL>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
set(listvar 10.0 1.1 2.1 8.0 2.0 3.1)
list(SORT listvar CASE SENSITIVE ORDER ASCENDING COMPARE NATURAL)
set (output "$<LIST:SORT,10.0;1.1;2.1;8.0;2.0;3.1,CASE:SENSITIVE,ORDER:ASCENDING,COMPARE:NATURAL>")
if (NOT output STREQUAL listvar)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:SORT..." ${errors})

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at SUBLIST-wrong-argument1.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:SUBLIST,a;b;c,3,-1>
begin index: 3 is out of range 0 - 2
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SUBLIST,a;b;c,3,-1>")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,8 @@
CMake Error at SUBLIST-wrong-argument2.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:SUBLIST,a;b;c,1,-2>
length: -2 should be -1 or greater
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:SUBLIST,a;b;c,1,-2>")

View File

@@ -0,0 +1,32 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar a b c d)
list(SUBLIST listvar 1 2 reference)
set (output "$<LIST:SUBLIST,a;b;c;d,1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(SUBLIST listvar 1 -1 reference)
set (output "$<LIST:SUBLIST,a;b;c;d,1,-1>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(SUBLIST listvar 1 0 reference)
set (output "$<LIST:SUBLIST,a;b;c;d,1,0>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(SUBLIST listvar 1 5 reference)
set (output "$<LIST:SUBLIST,a;b;c;d,1,5>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:SUBLIST..." ${errors})

View File

@@ -0,0 +1,50 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar alpha bravo charlie delta)
list(TRANSFORM listvar APPEND "_A" OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar APPEND "_A" AT 1 3 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,AT,1,3>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar APPEND "_A" AT 1 -2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,AT,1,-2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar APPEND "_A" FOR 1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,FOR,1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar APPEND "_A" FOR 1 -1 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,FOR,1,-1>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar APPEND "_A" FOR 1 -1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,FOR,1,-1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar APPEND "_A" REGEX "(r|t)a" OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,APPEND,_A,REGEX,(r|t)a>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:TRANSFORM,APPEND..." ${errors})

View File

@@ -0,0 +1,50 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar alpha bravo charlie delta)
list(TRANSFORM listvar PREPEND "P_" OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar PREPEND "P_" AT 1 3 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,AT,1,3>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar PREPEND "P_" AT 1 -2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,AT,1,-2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar PREPEND "P_" FOR 1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,FOR,1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar PREPEND "P_" FOR 1 -1 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,FOR,1,-1>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar PREPEND "P_" FOR 1 -1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,FOR,1,-1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar PREPEND "P_" REGEX "(r|t)a" OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,PREPEND,P_,REGEX,(r|t)a>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:TRANSFORM,PREPEND..." ${errors})

View File

@@ -0,0 +1,9 @@
CMake Error at TRANSFORM-REPLACE-invalid-replace1.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:TRANSFORM,a;b,REPLACE,\^a,b\\>
sub-command TRANSFORM, action REPLACE: replace-expression ends in a
backslash.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,REPLACE,^a,b\\>")

View File

@@ -0,0 +1,9 @@
CMake Error at TRANSFORM-REPLACE-invalid-replace2.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:TRANSFORM,a;b,REPLACE,\^a,\\b>
sub-command TRANSFORM, action REPLACE: Unknown escape "\\b" in
replace-expression.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,REPLACE,^a,\\b>")

View File

@@ -0,0 +1,8 @@
CMake Error at TRANSFORM-REPLACE-wrong-regex.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:TRANSFORM,a;b,REPLACE,\(a,b>
sub-command TRANSFORM, action REPLACE: Failed to compile regex "\(a".
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT result.txt CONTENT "$<LIST:TRANSFORM,a;b,REPLACE,(a,b>")

View File

@@ -0,0 +1,50 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar alpha bravo charlie delta)
list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" AT 1 3 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,AT,1,3>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" AT 1 -2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,AT,1,-2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" FOR 1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,FOR,1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" FOR 1 -1 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,FOR,1,-1>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" FOR 1 -1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,FOR,1,-1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar REPLACE "(.+a)$" "\\1_\\1" REGEX "(r|t)a" OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,REPLACE,(.+a)$,\1_\1,REGEX,(r|t)a>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:TRANSFORM,REPLACE..." ${errors})

View File

@@ -0,0 +1,50 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar " alpha" "bravo " " charlie " delta)
list(TRANSFORM listvar STRIP OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar STRIP AT 1 3 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,AT,1,3>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar STRIP AT 1 -2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,AT,1,-2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar STRIP FOR 1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,FOR,1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar STRIP FOR 1 -1 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,FOR,1,-1>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar STRIP FOR 1 -1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,FOR,1,-1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar STRIP REGEX "(r|t)a" OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM, alpha;bravo ; charlie ;delta,STRIP,REGEX,(r|t)a>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:TRANSFORM,STRIP..." ${errors})

View File

@@ -0,0 +1,50 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar ALPHA BRAVO CHARLIE DELTA)
list(TRANSFORM listvar TOLOWER OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOLOWER AT 1 3 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,AT,1,3>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOLOWER AT 1 -2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,AT,1,-2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOLOWER FOR 1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,FOR,1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOLOWER FOR 1 -1 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,FOR,1,-1>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOLOWER FOR 1 -1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,FOR,1,-1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOLOWER REGEX "(R|T)A" OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,ALPHA;BRAVO;CHARLIE;DELTA,TOLOWER,REGEX,(R|T)A>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:TRANSFORM,TOLOWER..." ${errors})

View File

@@ -0,0 +1,50 @@
include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
unset (errors)
set(listvar alpha bravo charlie delta)
list(TRANSFORM listvar TOUPPER OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOUPPER AT 1 3 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,AT,1,3>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOUPPER AT 1 -2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,AT,1,-2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOUPPER FOR 1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,FOR,1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOUPPER FOR 1 -1 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,FOR,1,-1>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOUPPER FOR 1 -1 2 OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,FOR,1,-1,2>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
list(TRANSFORM listvar TOUPPER REGEX "(r|t)a" OUTPUT_VARIABLE reference)
set (output "$<LIST:TRANSFORM,alpha;bravo;charlie;delta,TOUPPER,REGEX,(r|t)a>")
if (NOT output STREQUAL reference)
list (APPEND errors "returns bad value: ${output}")
endif()
check_errors("LIST:TRANSFORM,TOUPPER..." ${errors})

View File

@@ -0,0 +1,8 @@
CMake Error at missing-arg.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:TRANSFORM,ARG1,[A-Z]+(,ARG[0-9])?>
sub-command TRANSFORM, action [A-Z]+ expects (1|2) argument\(s\).
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

View File

@@ -0,0 +1,8 @@
CMake Error at TRANSFORM-selector-AT-no-arguments.cmake:[0-9]+ \(file\):
Error evaluating generator expression:
\$<LIST:TRANSFORM,a;b,TOUPPER,AT>
sub-command TRANSFORM, selector AT expects at least one numeric value.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)

Some files were not shown because too many files have changed in this diff Show More