cmGeneratorExpressionEvaluator.cxx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2012 Stephen Kelly <[email protected]>
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmGeneratorExpressionEvaluator.h"
  11. #include "cmAlgorithms.h"
  12. #include "cmGeneratorExpressionContext.h"
  13. #include "cmGeneratorExpressionNode.h"
  14. #include <algorithm>
  15. #include <sstream>
  16. GeneratorExpressionContent::GeneratorExpressionContent(
  17. const char* startContent, size_t length)
  18. : StartContent(startContent)
  19. , ContentLength(length)
  20. {
  21. }
  22. std::string GeneratorExpressionContent::GetOriginalExpression() const
  23. {
  24. return std::string(this->StartContent, this->ContentLength);
  25. }
  26. std::string GeneratorExpressionContent::ProcessArbitraryContent(
  27. const cmGeneratorExpressionNode* node, const std::string& identifier,
  28. cmGeneratorExpressionContext* context,
  29. cmGeneratorExpressionDAGChecker* dagChecker,
  30. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  31. pit) const
  32. {
  33. std::string result;
  34. const std::vector<
  35. std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator pend =
  36. this->ParamChildren.end();
  37. for (; pit != pend; ++pit) {
  38. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
  39. pit->begin();
  40. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
  41. pit->end();
  42. for (; it != end; ++it) {
  43. if (node->RequiresLiteralInput()) {
  44. if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) {
  45. reportError(context, this->GetOriginalExpression(), "$<" +
  46. identifier + "> expression requires literal input.");
  47. return std::string();
  48. }
  49. }
  50. result += (*it)->Evaluate(context, dagChecker);
  51. if (context->HadError) {
  52. return std::string();
  53. }
  54. }
  55. if ((pit + 1) != pend) {
  56. result += ",";
  57. }
  58. }
  59. if (node->RequiresLiteralInput()) {
  60. std::vector<std::string> parameters;
  61. parameters.push_back(result);
  62. return node->Evaluate(parameters, context, this, dagChecker);
  63. }
  64. return result;
  65. }
  66. std::string GeneratorExpressionContent::Evaluate(
  67. cmGeneratorExpressionContext* context,
  68. cmGeneratorExpressionDAGChecker* dagChecker) const
  69. {
  70. std::string identifier;
  71. {
  72. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
  73. this->IdentifierChildren.begin();
  74. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
  75. this->IdentifierChildren.end();
  76. for (; it != end; ++it) {
  77. identifier += (*it)->Evaluate(context, dagChecker);
  78. if (context->HadError) {
  79. return std::string();
  80. }
  81. }
  82. }
  83. const cmGeneratorExpressionNode* node =
  84. cmGeneratorExpressionNode::GetNode(identifier);
  85. if (!node) {
  86. reportError(context, this->GetOriginalExpression(),
  87. "Expression did not evaluate to a known generator expression");
  88. return std::string();
  89. }
  90. if (!node->GeneratesContent()) {
  91. if (node->NumExpectedParameters() == 1 &&
  92. node->AcceptsArbitraryContentParameter()) {
  93. if (this->ParamChildren.empty()) {
  94. reportError(context, this->GetOriginalExpression(),
  95. "$<" + identifier + "> expression requires a parameter.");
  96. }
  97. } else {
  98. std::vector<std::string> parameters;
  99. this->EvaluateParameters(node, identifier, context, dagChecker,
  100. parameters);
  101. }
  102. return std::string();
  103. }
  104. std::vector<std::string> parameters;
  105. this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
  106. if (context->HadError) {
  107. return std::string();
  108. }
  109. return node->Evaluate(parameters, context, this, dagChecker);
  110. }
  111. std::string GeneratorExpressionContent::EvaluateParameters(
  112. const cmGeneratorExpressionNode* node, const std::string& identifier,
  113. cmGeneratorExpressionContext* context,
  114. cmGeneratorExpressionDAGChecker* dagChecker,
  115. std::vector<std::string>& parameters) const
  116. {
  117. const int numExpected = node->NumExpectedParameters();
  118. {
  119. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  120. pit = this->ParamChildren.begin();
  121. const std::vector<
  122. std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator pend =
  123. this->ParamChildren.end();
  124. const bool acceptsArbitraryContent =
  125. node->AcceptsArbitraryContentParameter();
  126. int counter = 1;
  127. for (; pit != pend; ++pit, ++counter) {
  128. if (acceptsArbitraryContent && counter == numExpected) {
  129. std::string lastParam = this->ProcessArbitraryContent(
  130. node, identifier, context, dagChecker, pit);
  131. parameters.push_back(lastParam);
  132. return std::string();
  133. }
  134. std::string parameter;
  135. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
  136. pit->begin();
  137. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
  138. pit->end();
  139. for (; it != end; ++it) {
  140. parameter += (*it)->Evaluate(context, dagChecker);
  141. if (context->HadError) {
  142. return std::string();
  143. }
  144. }
  145. parameters.push_back(parameter);
  146. }
  147. }
  148. if ((numExpected > cmGeneratorExpressionNode::DynamicParameters &&
  149. (unsigned int)numExpected != parameters.size())) {
  150. if (numExpected == 0) {
  151. reportError(context, this->GetOriginalExpression(),
  152. "$<" + identifier + "> expression requires no parameters.");
  153. } else if (numExpected == 1) {
  154. reportError(context, this->GetOriginalExpression(), "$<" + identifier +
  155. "> expression requires "
  156. "exactly one parameter.");
  157. } else {
  158. std::ostringstream e;
  159. e << "$<" + identifier + "> expression requires " << numExpected
  160. << " comma separated parameters, but got " << parameters.size()
  161. << " instead.";
  162. reportError(context, this->GetOriginalExpression(), e.str());
  163. }
  164. return std::string();
  165. }
  166. if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters &&
  167. parameters.empty()) {
  168. reportError(context, this->GetOriginalExpression(), "$<" + identifier +
  169. "> expression requires at least one parameter.");
  170. }
  171. if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
  172. parameters.size() > 1) {
  173. reportError(context, this->GetOriginalExpression(), "$<" + identifier +
  174. "> expression requires one or zero parameters.");
  175. }
  176. return std::string();
  177. }
  178. GeneratorExpressionContent::~GeneratorExpressionContent()
  179. {
  180. cmDeleteAll(this->IdentifierChildren);
  181. std::for_each(this->ParamChildren.begin(), this->ParamChildren.end(),
  182. cmDeleteAll<std::vector<cmGeneratorExpressionEvaluator*> >);
  183. }