cmake_language(CALL): Accept empty ${var} expansions

Factor out an internal helper.  Generalize partial argument expansion
and call the helper on a clean boundary between raw arguments.
This commit is contained in:
Brad King
2020-09-21 16:01:56 -04:00
parent 4ebe9c4ce1
commit 4f33f3dcff
7 changed files with 76 additions and 74 deletions

View File

@@ -29,6 +29,38 @@ std::array<cm::static_string_view, 12> InvalidCommands{
} // clang-format on
};
bool cmCMakeLanguageCommandCALL(std::vector<cmListFileArgument> const& args,
std::string const& callCommand,
size_t startArg, cmExecutionStatus& status)
{
// ensure specified command is valid
// start/end flow control commands are not allowed
auto cmd = cmSystemTools::LowerCase(callCommand);
if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) !=
InvalidCommands.cend()) {
status.SetError(cmStrCat("invalid command specified: "_s, callCommand));
return false;
}
cmMakefile& makefile = status.GetMakefile();
cmListFileContext context = makefile.GetBacktrace().Top();
cmListFileFunction func;
func.Name = callCommand;
func.Line = context.Line;
// The rest of the arguments are passed to the function call above
for (size_t i = startArg; i < args.size(); ++i) {
cmListFileArgument lfarg;
lfarg.Delim = args[i].Delim;
lfarg.Line = context.Line;
lfarg.Value = args[i].Value;
func.Arguments.emplace_back(lfarg);
}
return makefile.ExecuteCommand(func, status);
}
bool cmCMakeLanguageCommandEVAL(std::vector<cmListFileArgument> const& args,
cmExecutionStatus& status)
{
@@ -64,82 +96,52 @@ bool cmCMakeLanguageCommandEVAL(std::vector<cmListFileArgument> const& args,
bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
cmExecutionStatus& status)
{
if (args.empty()) {
status.SetError("called with incorrect number of arguments");
return false;
}
std::vector<std::string> expArgs;
size_t rawArg = 0;
size_t expArg = 0;
cmMakefile& makefile = status.GetMakefile();
cmListFileContext context = makefile.GetBacktrace().Top();
bool result = false;
std::vector<std::string> dispatchExpandedArgs;
std::vector<cmListFileArgument> dispatchArgs;
dispatchArgs.emplace_back(args[0]);
makefile.ExpandArguments(dispatchArgs, dispatchExpandedArgs);
if (dispatchExpandedArgs.empty()) {
status.SetError("called with incorrect number of arguments");
return false;
}
if (dispatchExpandedArgs[0] == "CALL") {
if ((args.size() == 1 && dispatchExpandedArgs.size() != 2) ||
dispatchExpandedArgs.size() > 2) {
status.SetError("called with incorrect number of arguments");
return false;
}
// First argument is the name of the function to call
std::string callCommand;
size_t startArg;
if (dispatchExpandedArgs.size() == 1) {
std::vector<std::string> functionExpandedArg;
std::vector<cmListFileArgument> functionArg;
functionArg.emplace_back(args[1]);
makefile.ExpandArguments(functionArg, functionExpandedArg);
if (functionExpandedArg.size() != 1) {
status.SetError("called with incorrect number of arguments");
// Helper to consume and expand one raw argument at a time.
auto moreArgs = [&]() -> bool {
while (expArg >= expArgs.size()) {
if (rawArg >= args.size()) {
return false;
}
callCommand = functionExpandedArg[0];
startArg = 2;
} else {
callCommand = dispatchExpandedArgs[1];
startArg = 1;
std::vector<cmListFileArgument> tmpArg;
tmpArg.emplace_back(args[rawArg++]);
status.GetMakefile().ExpandArguments(tmpArg, expArgs);
}
return true;
};
// ensure specified command is valid
// start/end flow control commands are not allowed
auto cmd = cmSystemTools::LowerCase(callCommand);
if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) !=
InvalidCommands.cend()) {
status.SetError(cmStrCat("invalid command specified: "_s, callCommand));
if (!moreArgs()) {
status.SetError("called with incorrect number of arguments");
return false;
}
if (expArgs[expArg] == "CALL") {
++expArg; // Consume "CALL".
// CALL requires a command name.
if (!moreArgs()) {
status.SetError("CALL missing command name");
return false;
}
std::string const& callCommand = expArgs[expArg++];
// CALL accepts no further expanded arguments.
if (expArg != expArgs.size()) {
status.SetError("CALL command's arguments must be literal");
return false;
}
cmListFileFunction func;
func.Name = callCommand;
func.Line = context.Line;
// The rest of the arguments are passed to the function call above
for (size_t i = startArg; i < args.size(); ++i) {
cmListFileArgument lfarg;
lfarg.Delim = args[i].Delim;
lfarg.Line = context.Line;
lfarg.Value = args[i].Value;
func.Arguments.emplace_back(lfarg);
}
result = makefile.ExecuteCommand(func, status);
} else if (dispatchExpandedArgs[0] == "EVAL") {
return cmCMakeLanguageCommandEVAL(args, status);
} else {
status.SetError("called with unknown meta-operation");
// Run the CALL.
return cmCMakeLanguageCommandCALL(args, callCommand, rawArg, status);
}
return result;
if (expArgs[expArg] == "EVAL") {
return cmCMakeLanguageCommandEVAL(args, status);
}
status.SetError("called with unknown meta-operation");
return false;
}

View File

@@ -1,2 +1,2 @@
set (my_call "CALL")
cmake_language (${my_call} message "OK!")
cmake_language (${my_call} ${empty} message "OK!")

View File

@@ -3,4 +3,4 @@ function (itsok)
endfunction()
set (cmd CALL itsok)
cmake_language (${cmd})
cmake_language (${empty} ${cmd})

View File

@@ -1,4 +1,4 @@
CMake Error at call_expanded_command_and_arguments.cmake:2 \(cmake_language\):
cmake_language called with incorrect number of arguments
cmake_language CALL command's arguments must be literal
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@@ -1 +1 @@
cmake_language(CALL message WORKS!)
cmake_language(CALL ${empty} message WORKS!)

View File

@@ -1,2 +1,2 @@
CMake Error at call_no_parameters.cmake:1 \(cmake_language\):
cmake_language called with incorrect number of arguments
cmake_language CALL missing command name

View File

@@ -1,2 +1,2 @@
CMake Error at no_parameters.cmake:1 \(cmake_language\):
cmake_language called with incorrect number of arguments
cmake_language CALL missing command name