254 lines
8.7 KiB
C++
254 lines
8.7 KiB
C++
/*============================================================================
|
|
CMake - Cross Platform Makefile Generator
|
|
Copyright 2012 Stephen Kelly <steveire@gmail.com>
|
|
|
|
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 "cmMakefile.h"
|
|
|
|
#include "cmGeneratorExpressionEvaluator.h"
|
|
#include "cmGeneratorExpressionParser.h"
|
|
#include "cmGeneratorExpressionDAGChecker.h"
|
|
#include "cmGeneratorExpression.h"
|
|
#include "cmLocalGenerator.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmSourceFile.h"
|
|
#include "cmAlgorithms.h"
|
|
|
|
#include <cmsys/String.h>
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
|
|
#include "cmGeneratorExpressionNode.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
GeneratorExpressionContent::GeneratorExpressionContent(
|
|
const char *startContent,
|
|
size_t length)
|
|
: StartContent(startContent), ContentLength(length)
|
|
{
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string GeneratorExpressionContent::GetOriginalExpression() const
|
|
{
|
|
return std::string(this->StartContent, this->ContentLength);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string GeneratorExpressionContent::ProcessArbitraryContent(
|
|
const cmGeneratorExpressionNode *node,
|
|
const std::string &identifier,
|
|
cmGeneratorExpressionContext *context,
|
|
cmGeneratorExpressionDAGChecker *dagChecker,
|
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
|
|
pit) const
|
|
{
|
|
std::string result;
|
|
|
|
const
|
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
|
|
pend = this->ParamChildren.end();
|
|
for ( ; pit != pend; ++pit)
|
|
{
|
|
std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
|
|
= pit->begin();
|
|
const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
|
|
= pit->end();
|
|
for ( ; it != end; ++it)
|
|
{
|
|
if (node->RequiresLiteralInput())
|
|
{
|
|
if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text)
|
|
{
|
|
reportError(context, this->GetOriginalExpression(),
|
|
"$<" + identifier + "> expression requires literal input.");
|
|
return std::string();
|
|
}
|
|
}
|
|
result += (*it)->Evaluate(context, dagChecker);
|
|
if (context->HadError)
|
|
{
|
|
return std::string();
|
|
}
|
|
}
|
|
if ((pit + 1) != pend)
|
|
{
|
|
result += ",";
|
|
}
|
|
}
|
|
if (node->RequiresLiteralInput())
|
|
{
|
|
std::vector<std::string> parameters;
|
|
parameters.push_back(result);
|
|
return node->Evaluate(parameters, context, this, dagChecker);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string GeneratorExpressionContent::Evaluate(
|
|
cmGeneratorExpressionContext *context,
|
|
cmGeneratorExpressionDAGChecker *dagChecker) const
|
|
{
|
|
std::string identifier;
|
|
{
|
|
std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
|
|
= this->IdentifierChildren.begin();
|
|
const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
|
|
= this->IdentifierChildren.end();
|
|
for ( ; it != end; ++it)
|
|
{
|
|
identifier += (*it)->Evaluate(context, dagChecker);
|
|
if (context->HadError)
|
|
{
|
|
return std::string();
|
|
}
|
|
}
|
|
}
|
|
|
|
const cmGeneratorExpressionNode *node =
|
|
cmGeneratorExpressionNode::GetNode(identifier);
|
|
|
|
if (!node)
|
|
{
|
|
reportError(context, this->GetOriginalExpression(),
|
|
"Expression did not evaluate to a known generator expression");
|
|
return std::string();
|
|
}
|
|
|
|
if (!node->GeneratesContent())
|
|
{
|
|
if (node->NumExpectedParameters() == 1
|
|
&& node->AcceptsArbitraryContentParameter())
|
|
{
|
|
if (this->ParamChildren.empty())
|
|
{
|
|
reportError(context, this->GetOriginalExpression(),
|
|
"$<" + identifier + "> expression requires a parameter.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::string> parameters;
|
|
this->EvaluateParameters(node, identifier, context, dagChecker,
|
|
parameters);
|
|
}
|
|
return std::string();
|
|
}
|
|
|
|
std::vector<std::string> parameters;
|
|
this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
|
|
if (context->HadError)
|
|
{
|
|
return std::string();
|
|
}
|
|
|
|
return node->Evaluate(parameters, context, this, dagChecker);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string GeneratorExpressionContent::EvaluateParameters(
|
|
const cmGeneratorExpressionNode *node,
|
|
const std::string &identifier,
|
|
cmGeneratorExpressionContext *context,
|
|
cmGeneratorExpressionDAGChecker *dagChecker,
|
|
std::vector<std::string> ¶meters) const
|
|
{
|
|
const int numExpected = node->NumExpectedParameters();
|
|
{
|
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
|
|
pit = this->ParamChildren.begin();
|
|
const
|
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
|
|
pend = this->ParamChildren.end();
|
|
const bool acceptsArbitraryContent
|
|
= node->AcceptsArbitraryContentParameter();
|
|
int counter = 1;
|
|
for ( ; pit != pend; ++pit, ++counter)
|
|
{
|
|
if (acceptsArbitraryContent && counter == numExpected)
|
|
{
|
|
std::string lastParam = this->ProcessArbitraryContent(node, identifier,
|
|
context,
|
|
dagChecker,
|
|
pit);
|
|
parameters.push_back(lastParam);
|
|
return std::string();
|
|
}
|
|
else
|
|
{
|
|
std::string parameter;
|
|
std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
|
|
pit->begin();
|
|
const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
|
|
pit->end();
|
|
for ( ; it != end; ++it)
|
|
{
|
|
parameter += (*it)->Evaluate(context, dagChecker);
|
|
if (context->HadError)
|
|
{
|
|
return std::string();
|
|
}
|
|
}
|
|
parameters.push_back(parameter);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((numExpected > cmGeneratorExpressionNode::DynamicParameters
|
|
&& (unsigned int)numExpected != parameters.size()))
|
|
{
|
|
if (numExpected == 0)
|
|
{
|
|
reportError(context, this->GetOriginalExpression(),
|
|
"$<" + identifier + "> expression requires no parameters.");
|
|
}
|
|
else if (numExpected == 1)
|
|
{
|
|
reportError(context, this->GetOriginalExpression(),
|
|
"$<" + identifier + "> expression requires "
|
|
"exactly one parameter.");
|
|
}
|
|
else
|
|
{
|
|
std::ostringstream e;
|
|
e << "$<" + identifier + "> expression requires "
|
|
<< numExpected
|
|
<< " comma separated parameters, but got "
|
|
<< parameters.size() << " instead.";
|
|
reportError(context, this->GetOriginalExpression(), e.str());
|
|
}
|
|
return std::string();
|
|
}
|
|
|
|
if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters
|
|
&& parameters.empty())
|
|
{
|
|
reportError(context, this->GetOriginalExpression(), "$<" + identifier
|
|
+ "> expression requires at least one parameter.");
|
|
}
|
|
if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters
|
|
&& parameters.size() > 1)
|
|
{
|
|
reportError(context, this->GetOriginalExpression(), "$<" + identifier
|
|
+ "> expression requires one or zero parameters.");
|
|
}
|
|
return std::string();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
GeneratorExpressionContent::~GeneratorExpressionContent()
|
|
{
|
|
cmDeleteAll(this->IdentifierChildren);
|
|
std::for_each(this->ParamChildren.begin(), this->ParamChildren.end(),
|
|
cmDeleteAll<std::vector<cmGeneratorExpressionEvaluator*> >);
|
|
}
|