cmGeneratorExpressionEvaluator.cxx 6.2 KB

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