From ef38ff22f71ad0ffe83db42d903d26d4a41f4114 Mon Sep 17 00:00:00 2001 From: Regina Pfeifer Date: Tue, 23 Jul 2019 23:50:33 +0200 Subject: cm*FunctionBlocker: Extract function Replay --- Source/cmForEachCommand.cxx | 86 +++++++++-------- Source/cmFunctionCommand.cxx | 30 +++--- Source/cmIfCommand.cxx | 218 ++++++++++++++++++++++--------------------- Source/cmMacroCommand.cxx | 32 ++++--- Source/cmWhileCommand.cxx | 133 ++++++++++++++------------ 5 files changed, 272 insertions(+), 227 deletions(-) diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index b04f14c..af32040 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -25,6 +25,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& inStatus); std::vector Args; std::vector Functions; @@ -63,44 +65,7 @@ bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, return false; } - // at end of for each execute recorded commands - // store the old value - std::string oldDef; - if (mf.GetDefinition(this->Args[0])) { - oldDef = mf.GetDefinition(this->Args[0]); - } - - for (std::string const& arg : cmMakeRange(this->Args).advance(1)) { - // set the variable to the loop value - mf.AddDefinition(this->Args[0], arg); - // Invoke all the functions that were collected in the block. - cmExecutionStatus status(mf); - for (cmListFileFunction const& func : this->Functions) { - status.Clear(); - mf.ExecuteCommand(func, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); - return true; - } - if (status.GetBreakInvoked()) { - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); - return true; - } - if (status.GetContinueInvoked()) { - break; - } - if (cmSystemTools::GetFatalErrorOccured()) { - return true; - } - } - } - - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); - return true; + return this->Replay(this->Functions, inStatus); } // close out a nested foreach this->Depth--; @@ -129,6 +94,51 @@ bool cmForEachFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmForEachFunctionBlocker::Replay( + std::vector const& functions, + cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + // at end of for each execute recorded commands + // store the old value + std::string oldDef; + if (mf.GetDefinition(this->Args[0])) { + oldDef = mf.GetDefinition(this->Args[0]); + } + + for (std::string const& arg : cmMakeRange(this->Args).advance(1)) { + // set the variable to the loop value + mf.AddDefinition(this->Args[0], arg); + // Invoke all the functions that were collected in the block. + cmExecutionStatus status(mf); + for (cmListFileFunction const& func : functions) { + status.Clear(); + mf.ExecuteCommand(func, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; + } + if (status.GetBreakInvoked()) { + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; + } + if (status.GetContinueInvoked()) { + break; + } + if (cmSystemTools::GetFatalErrorOccured()) { + return true; + } + } + } + + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; +} + bool cmForEachCommand::InitialPass(std::vector const& args, cmExecutionStatus&) { diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index f8230f1..51b6970 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -110,6 +110,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& status); std::vector Args; std::vector Functions; @@ -117,7 +119,7 @@ public: }; bool cmFunctionFunctionBlocker::IsFunctionBlocked( - const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) + const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus& status) { // record commands until we hit the ENDFUNCTION // at the ENDFUNCTION call we shift gears and start looking for invocations @@ -126,16 +128,8 @@ bool cmFunctionFunctionBlocker::IsFunctionBlocked( } else if (lff.Name.Lower == "endfunction") { // if this is the endfunction for this function then execute if (!this->Depth) { - // create a new command and add it to cmake - cmFunctionHelperCommand f; - f.Args = this->Args; - f.Functions = this->Functions; - f.FilePath = this->GetStartingContext().FilePath; - mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); - // remove the function blocker now that the function is defined - mf.RemoveFunctionBlocker(this, lff); - return true; + auto self = mf.RemoveFunctionBlocker(this, lff); + return this->Replay(this->Functions, status); } // decrement for each nested function that ends this->Depth--; @@ -165,6 +159,20 @@ bool cmFunctionFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmFunctionFunctionBlocker::Replay( + std::vector const& functions, cmExecutionStatus& status) +{ + cmMakefile& mf = status.GetMakefile(); + // create a new command and add it to cmake + cmFunctionHelperCommand f; + f.Args = this->Args; + f.Functions = functions; + f.FilePath = this->GetStartingContext().FilePath; + mf.RecordPolicies(f.Policies); + mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); + return true; +} + bool cmFunctionCommand::InitialPass(std::vector const& args, cmExecutionStatus&) { diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 20fe2f8..95f8177 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -36,6 +36,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& inStatus); std::vector Args; std::vector Functions; @@ -64,110 +66,7 @@ bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, return false; } - // execute the functions for the true parts of the if statement - cmExecutionStatus status(mf); - int scopeDepth = 0; - for (cmListFileFunction const& func : this->Functions) { - // keep track of scope depth - if (func.Name.Lower == "if") { - scopeDepth++; - } - if (func.Name.Lower == "endif") { - scopeDepth--; - } - // watch for our state change - if (scopeDepth == 0 && func.Name.Lower == "else") { - - if (this->ElseSeen) { - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, - "A duplicate ELSE command was found inside an IF block.", bt); - cmSystemTools::SetFatalErrorOccured(); - return true; - } - - this->IsBlocking = this->HasRun; - this->HasRun = true; - this->ElseSeen = true; - - // if trace is enabled, print a (trivially) evaluated "else" - // statement - if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) { - mf.PrintCommandTrace(func); - } - } else if (scopeDepth == 0 && func.Name.Lower == "elseif") { - if (this->ElseSeen) { - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, - "An ELSEIF command was found after an ELSE command.", bt); - cmSystemTools::SetFatalErrorOccured(); - return true; - } - - if (this->HasRun) { - this->IsBlocking = true; - } else { - // if trace is enabled, print the evaluated "elseif" statement - if (mf.GetCMakeInstance()->GetTrace()) { - mf.PrintCommandTrace(func); - } - - std::string errorString; - - std::vector expandedArguments; - mf.ExpandArguments(func.Arguments, expandedArguments); - - MessageType messType; - - cmListFileContext conditionContext = - cmListFileContext::FromCommandContext( - func, this->GetStartingContext().FilePath); - - cmConditionEvaluator conditionEvaluator(mf, conditionContext, - mf.GetBacktrace(func)); - - bool isTrue = conditionEvaluator.IsTrue(expandedArguments, - errorString, messType); - - if (!errorString.empty()) { - std::string err = cmIfCommandError(expandedArguments); - err += errorString; - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage(messType, err, bt); - if (messType == MessageType::FATAL_ERROR) { - cmSystemTools::SetFatalErrorOccured(); - return true; - } - } - - if (isTrue) { - this->IsBlocking = false; - this->HasRun = true; - } - } - } - - // should we execute? - else if (!this->IsBlocking) { - status.Clear(); - mf.ExecuteCommand(func, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - return true; - } - if (status.GetBreakInvoked()) { - inStatus.SetBreakInvoked(); - return true; - } - if (status.GetContinueInvoked()) { - inStatus.SetContinueInvoked(); - return true; - } - } - } - return true; + return this->Replay(this->Functions, inStatus); } } @@ -193,6 +92,117 @@ bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmIfFunctionBlocker::Replay( + std::vector const& functions, + cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + // execute the functions for the true parts of the if statement + cmExecutionStatus status(mf); + int scopeDepth = 0; + for (cmListFileFunction const& func : functions) { + // keep track of scope depth + if (func.Name.Lower == "if") { + scopeDepth++; + } + if (func.Name.Lower == "endif") { + scopeDepth--; + } + // watch for our state change + if (scopeDepth == 0 && func.Name.Lower == "else") { + + if (this->ElseSeen) { + cmListFileBacktrace bt = mf.GetBacktrace(func); + mf.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "A duplicate ELSE command was found inside an IF block.", bt); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + + this->IsBlocking = this->HasRun; + this->HasRun = true; + this->ElseSeen = true; + + // if trace is enabled, print a (trivially) evaluated "else" + // statement + if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) { + mf.PrintCommandTrace(func); + } + } else if (scopeDepth == 0 && func.Name.Lower == "elseif") { + if (this->ElseSeen) { + cmListFileBacktrace bt = mf.GetBacktrace(func); + mf.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "An ELSEIF command was found after an ELSE command.", bt); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + + if (this->HasRun) { + this->IsBlocking = true; + } else { + // if trace is enabled, print the evaluated "elseif" statement + if (mf.GetCMakeInstance()->GetTrace()) { + mf.PrintCommandTrace(func); + } + + std::string errorString; + + std::vector expandedArguments; + mf.ExpandArguments(func.Arguments, expandedArguments); + + MessageType messType; + + cmListFileContext conditionContext = + cmListFileContext::FromCommandContext( + func, this->GetStartingContext().FilePath); + + cmConditionEvaluator conditionEvaluator(mf, conditionContext, + mf.GetBacktrace(func)); + + bool isTrue = + conditionEvaluator.IsTrue(expandedArguments, errorString, messType); + + if (!errorString.empty()) { + std::string err = cmIfCommandError(expandedArguments); + err += errorString; + cmListFileBacktrace bt = mf.GetBacktrace(func); + mf.GetCMakeInstance()->IssueMessage(messType, err, bt); + if (messType == MessageType::FATAL_ERROR) { + cmSystemTools::SetFatalErrorOccured(); + return true; + } + } + + if (isTrue) { + this->IsBlocking = false; + this->HasRun = true; + } + } + } + + // should we execute? + else if (!this->IsBlocking) { + status.Clear(); + mf.ExecuteCommand(func, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + return true; + } + if (status.GetBreakInvoked()) { + inStatus.SetBreakInvoked(); + return true; + } + if (status.GetContinueInvoked()) { + inStatus.SetContinueInvoked(); + return true; + } + } + } + return true; +} + //========================================================================= bool cmIfCommand(std::vector const& args, cmExecutionStatus& inStatus) diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index a123f22..e82d6fa 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -144,6 +144,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& status); std::vector Args; std::vector Functions; @@ -152,7 +154,7 @@ public: bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) + cmExecutionStatus& status) { // record commands until we hit the ENDMACRO // at the ENDMACRO call we shift gears and start looking for invocations @@ -161,17 +163,8 @@ bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, } else if (lff.Name.Lower == "endmacro") { // if this is the endmacro for this macro then execute if (!this->Depth) { - mf.AppendProperty("MACROS", this->Args[0].c_str()); - // create a new command and add it to cmake - cmMacroHelperCommand f; - f.Args = this->Args; - f.Functions = this->Functions; - f.FilePath = this->GetStartingContext().FilePath; - mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); - // remove the function blocker now that the macro is defined - mf.RemoveFunctionBlocker(this, lff); - return true; + auto self = mf.RemoveFunctionBlocker(this, lff); + return this->Replay(this->Functions, status); } // decrement for each nested macro that ends this->Depth--; @@ -201,6 +194,21 @@ bool cmMacroFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmMacroFunctionBlocker::Replay( + std::vector const& functions, cmExecutionStatus& status) +{ + cmMakefile& mf = status.GetMakefile(); + mf.AppendProperty("MACROS", this->Args[0].c_str()); + // create a new command and add it to cmake + cmMacroHelperCommand f; + f.Args = this->Args; + f.Functions = functions; + f.FilePath = this->GetStartingContext().FilePath; + mf.RecordPolicies(f.Policies); + mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); + return true; +} + bool cmMacroCommand::InitialPass(std::vector const& args, cmExecutionStatus&) { diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 914860c..025d14a 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -24,6 +24,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& inStatus); std::vector Args; std::vector Functions; @@ -62,68 +64,7 @@ bool cmWhileFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, if (!fb) { return false; } - - std::string errorString; - - std::vector expandedArguments; - mf.ExpandArguments(this->Args, expandedArguments); - MessageType messageType; - - cmListFileContext execContext = this->GetStartingContext(); - - cmCommandContext commandContext; - commandContext.Line = execContext.Line; - commandContext.Name = execContext.Name; - - cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(), - mf.GetBacktrace(commandContext)); - - bool isTrue = - conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); - - while (isTrue) { - if (!errorString.empty()) { - std::string err = "had incorrect arguments: "; - for (cmListFileArgument const& arg : this->Args) { - err += (arg.Delim ? "\"" : ""); - err += arg.Value; - err += (arg.Delim ? "\"" : ""); - err += " "; - } - err += "("; - err += errorString; - err += ")."; - mf.IssueMessage(messageType, err); - if (messageType == MessageType::FATAL_ERROR) { - cmSystemTools::SetFatalErrorOccured(); - return true; - } - } - - // Invoke all the functions that were collected in the block. - for (cmListFileFunction const& fn : this->Functions) { - cmExecutionStatus status(mf); - mf.ExecuteCommand(fn, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - return true; - } - if (status.GetBreakInvoked()) { - return true; - } - if (status.GetContinueInvoked()) { - break; - } - if (cmSystemTools::GetFatalErrorOccured()) { - return true; - } - } - expandedArguments.clear(); - mf.ExpandArguments(this->Args, expandedArguments); - isTrue = conditionEvaluator.IsTrue(expandedArguments, errorString, - messageType); - } - return true; + return this->Replay(this->Functions, inStatus); } // decrement for each nested while that ends this->Depth--; @@ -149,6 +90,74 @@ bool cmWhileFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmWhileFunctionBlocker::Replay( + std::vector const& functions, + cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + std::string errorString; + + std::vector expandedArguments; + mf.ExpandArguments(this->Args, expandedArguments); + MessageType messageType; + + cmListFileContext execContext = this->GetStartingContext(); + + cmCommandContext commandContext; + commandContext.Line = execContext.Line; + commandContext.Name = execContext.Name; + + cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(), + mf.GetBacktrace(commandContext)); + + bool isTrue = + conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); + + while (isTrue) { + if (!errorString.empty()) { + std::string err = "had incorrect arguments: "; + for (cmListFileArgument const& arg : this->Args) { + err += (arg.Delim ? "\"" : ""); + err += arg.Value; + err += (arg.Delim ? "\"" : ""); + err += " "; + } + err += "("; + err += errorString; + err += ")."; + mf.IssueMessage(messageType, err); + if (messageType == MessageType::FATAL_ERROR) { + cmSystemTools::SetFatalErrorOccured(); + return true; + } + } + + // Invoke all the functions that were collected in the block. + for (cmListFileFunction const& fn : functions) { + cmExecutionStatus status(mf); + mf.ExecuteCommand(fn, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + return true; + } + if (status.GetBreakInvoked()) { + return true; + } + if (status.GetContinueInvoked()) { + break; + } + if (cmSystemTools::GetFatalErrorOccured()) { + return true; + } + } + expandedArguments.clear(); + mf.ExpandArguments(this->Args, expandedArguments); + isTrue = + conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); + } + return true; +} + bool cmWhileCommand(std::vector const& args, cmExecutionStatus& status) { -- cgit v0.12