Commit ef38ff22 authored by wahikihiki's avatar wahikihiki

cm*FunctionBlocker: Extract function Replay

parent b51fba62
......@@ -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<cmListFileFunction> const& functions,
cmExecutionStatus& inStatus);
std::vector<std::string> Args;
std::vector<cmListFileFunction> 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<cmListFileFunction> 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<std::string> const& args,
cmExecutionStatus&)
{
......
......@@ -110,6 +110,8 @@ public:
bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf,
cmExecutionStatus&) override;
bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override;
bool Replay(std::vector<cmListFileFunction> const& functions,
cmExecutionStatus& status);
std::vector<std::string> Args;
std::vector<cmListFileFunction> 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<cmListFileFunction> 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<std::string> const& args,
cmExecutionStatus&)
{
......
......@@ -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<cmListFileFunction> const& functions,
cmExecutionStatus& inStatus);
std::vector<cmListFileArgument> Args;
std::vector<cmListFileFunction> 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<cmExpandedCommandArgument> 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<cmListFileFunction> 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<cmExpandedCommandArgument> 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<cmListFileArgument> const& args,
cmExecutionStatus& inStatus)
......
......@@ -144,6 +144,8 @@ public:
bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf,
cmExecutionStatus&) override;
bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override;
bool Replay(std::vector<cmListFileFunction> const& functions,
cmExecutionStatus& status);
std::vector<std::string> Args;
std::vector<cmListFileFunction> 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<cmListFileFunction> 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<std::string> const& args,
cmExecutionStatus&)
{
......
......@@ -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<cmListFileFunction> const& functions,
cmExecutionStatus& inStatus);
std::vector<cmListFileArgument> Args;
std::vector<cmListFileFunction> Functions;
......@@ -62,68 +64,7 @@ bool cmWhileFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
if (!fb) {
return false;
}
std::string errorString;
std::vector<cmExpandedCommandArgument> 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<cmListFileFunction> const& functions,
cmExecutionStatus& inStatus)
{
cmMakefile& mf = inStatus.GetMakefile();
std::string errorString;
std::vector<cmExpandedCommandArgument> 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<cmListFileArgument> const& args,
cmExecutionStatus& status)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment