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