continue: Add a new CMake language command for loop continuation (#14013)

Inspired-by: Doug Barbieri
Signed-off-by: Gregor Jasny <gjasny@googlemail.com>
This commit is contained in:
Gregor Jasny 2014-11-29 17:56:18 +01:00 committed by Brad King
parent 8e75f1d2fa
commit 0de867dde2
31 changed files with 241 additions and 2 deletions

View File

@ -8,3 +8,5 @@ Break from an enclosing foreach or while loop.
break() break()
Breaks from an enclosing foreach loop or while loop Breaks from an enclosing foreach loop or while loop
See also the :command:`continue` command.

12
Help/command/continue.rst Normal file
View File

@ -0,0 +1,12 @@
continue
--------
Continue to the top of enclosing foreach or while loop.
::
continue()
The ``continue`` command allows a cmake script to abort the rest of a block
in a :command:`foreach` or :command:`while` loop, and start at the top of
the next iteration. See also the :command:`break` command.

View File

@ -31,6 +31,7 @@ These commands may be used freely in CMake projects.
/command/cmake_minimum_required /command/cmake_minimum_required
/command/cmake_policy /command/cmake_policy
/command/configure_file /command/configure_file
/command/continue
/command/create_test_sourcelist /command/create_test_sourcelist
/command/define_property /command/define_property
/command/elseif /command/elseif

View File

@ -469,8 +469,10 @@ Loops
The :command:`foreach`/:command:`endforeach` and The :command:`foreach`/:command:`endforeach` and
:command:`while`/:command:`endwhile` commands delimit code :command:`while`/:command:`endwhile` commands delimit code
blocks to be executed in a loop. The :command:`break` command blocks to be executed in a loop. Inside such blocks the
may be used inside such blocks to terminate the loop early. :command:`break` command may be used to terminate the loop
early whereas the :command:`continue` command may be used
to start with the next iteration immediately.
Command Definitions Command Definitions
------------------- -------------------

View File

@ -0,0 +1,6 @@
add-continue-command
--------------------
* A new :command:`continue` command was added that can be called inside loop
contexts to end the current iteration and start the next one at the top of
the loop block.

View File

@ -28,6 +28,7 @@
#include "cmCMakePolicyCommand.cxx" #include "cmCMakePolicyCommand.cxx"
#include "cmCommandArgumentsHelper.cxx" #include "cmCommandArgumentsHelper.cxx"
#include "cmConfigureFileCommand.cxx" #include "cmConfigureFileCommand.cxx"
#include "cmContinueCommand.cxx"
#include "cmCoreTryCompile.cxx" #include "cmCoreTryCompile.cxx"
#include "cmCreateTestSourceList.cxx" #include "cmCreateTestSourceList.cxx"
#include "cmDefinePropertyCommand.cxx" #include "cmDefinePropertyCommand.cxx"
@ -70,6 +71,7 @@ void GetBootstrapCommands1(std::list<cmCommand*>& commands)
commands.push_back(new cmCMakeMinimumRequired); commands.push_back(new cmCMakeMinimumRequired);
commands.push_back(new cmCMakePolicyCommand); commands.push_back(new cmCMakePolicyCommand);
commands.push_back(new cmConfigureFileCommand); commands.push_back(new cmConfigureFileCommand);
commands.push_back(new cmContinueCommand);
commands.push_back(new cmCreateTestSourceList); commands.push_back(new cmCreateTestSourceList);
commands.push_back(new cmDefinePropertyCommand); commands.push_back(new cmDefinePropertyCommand);
commands.push_back(new cmElseCommand); commands.push_back(new cmElseCommand);

View File

@ -0,0 +1,39 @@
/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2000-2014 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#include "cmContinueCommand.h"
// cmContinueCommand
bool cmContinueCommand::InitialPass(std::vector<std::string> const &args,
cmExecutionStatus &status)
{
if(!this->Makefile->IsLoopBlock())
{
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
"A CONTINUE command was found outside of a "
"proper FOREACH or WHILE loop scope.");
cmSystemTools::SetFatalErrorOccured();
return true;
}
status.SetContinueInvoked(true);
if(!args.empty())
{
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
"The CONTINUE command does not accept any "
"arguments.");
cmSystemTools::SetFatalErrorOccured();
return true;
}
return true;
}

View File

@ -0,0 +1,55 @@
/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2000-2014 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#ifndef cmContinueCommand_h
#define cmContinueCommand_h
#include "cmCommand.h"
/** \class cmContinueCommand
* \brief Continue from an enclosing foreach or while loop
*
* cmContinueCommand returns from an enclosing foreach or while loop
*/
class cmContinueCommand : public cmCommand
{
public:
/**
* This is a virtual constructor for the command.
*/
virtual cmCommand* Clone()
{
return new cmContinueCommand;
}
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
virtual bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus &status);
/**
* This determines if the command is invoked when in script mode.
*/
virtual bool IsScriptable() const { return true; }
/**
* The name of the command as specified in CMakeList.txt.
*/
virtual std::string GetName() const { return "continue"; }
cmTypeMacro(cmContinueCommand, cmCommand);
};
#endif

View File

@ -36,10 +36,16 @@ public:
virtual bool GetBreakInvoked() virtual bool GetBreakInvoked()
{ return this->BreakInvoked; } { return this->BreakInvoked; }
virtual void SetContinueInvoked(bool val)
{ this->ContinueInvoked = val; }
virtual bool GetContinueInvoked()
{ return this->ContinueInvoked; }
virtual void Clear() virtual void Clear()
{ {
this->ReturnInvoked = false; this->ReturnInvoked = false;
this->BreakInvoked = false; this->BreakInvoked = false;
this->ContinueInvoked = false;
this->NestedError = false; this->NestedError = false;
} }
virtual void SetNestedError(bool val) { this->NestedError = val; } virtual void SetNestedError(bool val) { this->NestedError = val; }
@ -49,6 +55,7 @@ public:
protected: protected:
bool ReturnInvoked; bool ReturnInvoked;
bool BreakInvoked; bool BreakInvoked;
bool ContinueInvoked;
bool NestedError; bool NestedError;
}; };

View File

@ -69,6 +69,10 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
mf.AddDefinition(this->Args[0],oldDef.c_str()); mf.AddDefinition(this->Args[0],oldDef.c_str());
return true; return true;
} }
if (status.GetContinueInvoked())
{
break;
}
if(cmSystemTools::GetFatalErrorOccured() ) if(cmSystemTools::GetFatalErrorOccured() )
{ {
return true; return true;

View File

@ -151,6 +151,11 @@ IsFunctionBlocked(const cmListFileFunction& lff,
inStatus.SetBreakInvoked(true); inStatus.SetBreakInvoked(true);
return true; return true;
} }
if (status.GetContinueInvoked())
{
inStatus.SetContinueInvoked(true);
return true;
}
} }
} }
return true; return true;

View File

@ -83,6 +83,10 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
{ {
return true; return true;
} }
if (status.GetContinueInvoked())
{
break;
}
if(cmSystemTools::GetFatalErrorOccured() ) if(cmSystemTools::GetFatalErrorOccured() )
{ {
return true; return true;

View File

@ -102,6 +102,7 @@ add_RunCMake_test(add_dependencies)
add_RunCMake_test(build_command) add_RunCMake_test(build_command)
add_RunCMake_test(export) add_RunCMake_test(export)
add_RunCMake_test(cmake_minimum_required) add_RunCMake_test(cmake_minimum_required)
add_RunCMake_test(continue)
add_RunCMake_test(file) add_RunCMake_test(file)
add_RunCMake_test(find_package) add_RunCMake_test(find_package)
add_RunCMake_test(get_filename_component) add_RunCMake_test(get_filename_component)

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.1)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1,10 @@
list(APPEND foo 1 2 3 4 5)
message(STATUS "start")
foreach(iter IN LISTS foo)
if("${iter}" EQUAL 1 OR "${iter}" EQUAL 3 OR "${iter}" EQUAL 5)
continue()
endif()
message(STATUS "${iter}")
endforeach()
message(STATUS "end")

View File

@ -0,0 +1,4 @@
-- start
-- 2
-- 4
-- end

View File

@ -0,0 +1,8 @@
message(STATUS "start")
foreach(iter RANGE 1 5)
if("${iter}" EQUAL 1 OR "${iter}" EQUAL 3 OR "${iter}" EQUAL 5)
continue()
endif()
message(STATUS "${iter}")
endforeach()
message(STATUS "end")

View File

@ -0,0 +1,6 @@
-- start
-- 7 2
-- 7 4
-- 9 2
-- 9 4
-- end

View File

@ -0,0 +1,13 @@
message(STATUS "start")
foreach(outer RANGE 7 9)
if("${outer}" EQUAL 8)
continue()
endif()
foreach(inner RANGE 1 5)
if("${inner}" EQUAL 1 OR "${inner}" EQUAL 3 OR "${inner}" EQUAL 5)
continue()
endif()
message(STATUS "${outer} ${inner}")
endforeach()
endforeach()
message(STATUS "end")

View File

@ -0,0 +1,6 @@
-- start
-- a
-- aa
-- aaaa
-- aaaaa
-- end

View File

@ -0,0 +1,10 @@
message(STATUS "start")
unset(iter)
while(NOT "${iter}" STREQUAL "aaaaa")
set(iter "${iter}a")
if("${iter}" STREQUAL "aaa")
continue()
endif()
message(STATUS "${iter}")
endwhile()
message(STATUS "end")

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at NoArgumentsToContinue.cmake:2 \(continue\):
The CONTINUE command does not accept any arguments.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,3 @@
foreach(i RANGE 1 2)
continue(1)
endforeach()

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
CMake Error at NoEnclosingBlock.cmake:1 \(continue\):
A CONTINUE command was found outside of a proper FOREACH or WHILE loop
scope.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
continue()

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,6 @@
CMake Error at NoEnclosingBlockInFunction.cmake:2 \(continue\):
A CONTINUE command was found outside of a proper FOREACH or WHILE loop
scope.
Call Stack \(most recent call first\):
NoEnclosingBlockInFunction.cmake:6 \(foo\)
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,8 @@
function(foo)
continue()
endfunction(foo)
foreach(i RANGE 1 2)
foo()
message(STATUS "Hello World")
endforeach()

View File

@ -0,0 +1,9 @@
include(RunCMake)
run_cmake(ContinueForeach)
run_cmake(ContinueForEachInLists)
run_cmake(ContinueNestedForeach)
run_cmake(ContinueWhile)
run_cmake(NoArgumentsToContinue)
run_cmake(NoEnclosingBlock)
run_cmake(NoEnclosingBlockInFunction)