/*============================================================================ CMake - Cross Platform Makefile Generator Copyright 2012 Stephen Kelly 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 #include #include #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 >::const_iterator pit) const { std::string result; const std::vector >::const_iterator pend = this->ParamChildren.end(); for ( ; pit != pend; ++pit) { std::vector::const_iterator it = pit->begin(); const std::vector::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 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::const_iterator it = this->IdentifierChildren.begin(); const std::vector::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 parameters; this->EvaluateParameters(node, identifier, context, dagChecker, parameters); } return std::string(); } std::vector 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 ¶meters) const { const int numExpected = node->NumExpectedParameters(); { std::vector >::const_iterator pit = this->ParamChildren.begin(); const std::vector >::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::const_iterator it = pit->begin(); const std::vector::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 >); }