resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmGeneratorExpressionParser.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 "cmGeneratorExpressionParser.h"
4
5 #include <cassert>
6 #include <cstddef>
7 #include <utility>
8
9 #include <cm/memory>
10 #include <cmext/algorithm>
11 #include <cmext/memory>
12
13 #include "cmGeneratorExpressionEvaluator.h"
14
15 cmGeneratorExpressionParser::cmGeneratorExpressionParser(
16   std::vector<cmGeneratorExpressionToken> tokens)
17   : Tokens(std::move(tokens))
18 {
19 }
20
21 void cmGeneratorExpressionParser::Parse(
22   cmGeneratorExpressionEvaluatorVector& result)
23 {
24   this->it = this->Tokens.begin();
25
26   while (this->it != this->Tokens.end()) {
27     this->ParseContent(result);
28   }
29 }
30
31 static void extendText(
32   cmGeneratorExpressionEvaluatorVector& result,
33   std::vector<cmGeneratorExpressionToken>::const_iterator it)
34 {
35   if (!result.empty() &&
36       (*(result.end() - 1))->GetType() ==
37         cmGeneratorExpressionEvaluator::Text) {
38     cm::static_reference_cast<TextContent>(*(result.end() - 1))
39       .Extend(it->Length);
40   } else {
41     auto textContent = cm::make_unique<TextContent>(it->Content, it->Length);
42     result.push_back(std::move(textContent));
43   }
44 }
45
46 static void extendResult(
47   cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector& result,
48   cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector&& contents)
49 {
50   if (!result.empty() &&
51       (*(result.end() - 1))->GetType() ==
52         cmGeneratorExpressionEvaluator::Text &&
53       contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) {
54     cm::static_reference_cast<TextContent>(*(result.end() - 1))
55       .Extend(
56         cm::static_reference_cast<TextContent>(contents.front()).GetLength());
57     contents.erase(contents.begin());
58   }
59   cm::append(result, std::move(contents));
60 }
61
62 void cmGeneratorExpressionParser::ParseGeneratorExpression(
63   cmGeneratorExpressionEvaluatorVector& result)
64 {
65   assert(this->it != this->Tokens.end());
66   unsigned int nestedLevel = this->NestingLevel;
67   ++this->NestingLevel;
68
69   auto startToken = this->it - 1;
70
71   cmGeneratorExpressionEvaluatorVector identifier;
72   while (this->it->TokenType != cmGeneratorExpressionToken::EndExpression &&
73          this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator) {
74     if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
75       extendText(identifier, this->it);
76       ++this->it;
77     } else {
78       this->ParseContent(identifier);
79     }
80     if (this->it == this->Tokens.end()) {
81       break;
82     }
83   }
84   if (identifier.empty()) {
85     // ERROR
86   }
87
88   if (this->it != this->Tokens.end() &&
89       this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
90     auto content = cm::make_unique<GeneratorExpressionContent>(
91       startToken->Content,
92       this->it->Content - startToken->Content + this->it->Length);
93     assert(this->it != this->Tokens.end());
94     ++this->it;
95     --this->NestingLevel;
96     content->SetIdentifier(std::move(identifier));
97     result.push_back(std::move(content));
98     return;
99   }
100
101   std::vector<cmGeneratorExpressionEvaluatorVector> parameters;
102   std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
103     commaTokens;
104   std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
105
106   bool emptyParamTermination = false;
107
108   if (this->it != this->Tokens.end() &&
109       this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
110     colonToken = this->it;
111     parameters.resize(parameters.size() + 1);
112     assert(this->it != this->Tokens.end());
113     ++this->it;
114     if (this->it == this->Tokens.end()) {
115       emptyParamTermination = true;
116     }
117
118     while (this->it != this->Tokens.end() &&
119            this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
120       commaTokens.push_back(this->it);
121       parameters.resize(parameters.size() + 1);
122       assert(this->it != this->Tokens.end());
123       ++this->it;
124       if (this->it == this->Tokens.end()) {
125         emptyParamTermination = true;
126       }
127     }
128     while (this->it != this->Tokens.end() &&
129            this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
130       extendText(*(parameters.end() - 1), this->it);
131       assert(this->it != this->Tokens.end());
132       ++this->it;
133     }
134     while (this->it != this->Tokens.end() &&
135            this->it->TokenType != cmGeneratorExpressionToken::EndExpression) {
136       this->ParseContent(*(parameters.end() - 1));
137       if (this->it == this->Tokens.end()) {
138         break;
139       }
140       while (this->it != this->Tokens.end() &&
141              this->it->TokenType ==
142                cmGeneratorExpressionToken::CommaSeparator) {
143         commaTokens.push_back(this->it);
144         parameters.resize(parameters.size() + 1);
145         assert(this->it != this->Tokens.end());
146         ++this->it;
147         if (this->it == this->Tokens.end()) {
148           emptyParamTermination = true;
149         }
150       }
151       while (this->it != this->Tokens.end() &&
152              this->it->TokenType ==
153                cmGeneratorExpressionToken::ColonSeparator) {
154         extendText(*(parameters.end() - 1), this->it);
155         assert(this->it != this->Tokens.end());
156         ++this->it;
157       }
158     }
159     if (this->it != this->Tokens.end() &&
160         this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
161       --this->NestingLevel;
162       assert(this->it != this->Tokens.end());
163       ++this->it;
164     }
165   }
166
167   if (nestedLevel != this->NestingLevel) {
168     // There was a '$<' in the text, but no corresponding '>'. Rebuild to
169     // treat the '$<' as having been plain text, along with the
170     // corresponding : and , tokens that might have been found.
171     extendText(result, startToken);
172     extendResult(result, std::move(identifier));
173     if (!parameters.empty()) {
174       extendText(result, colonToken);
175
176       auto pit = parameters.begin();
177       const auto pend = parameters.end();
178       auto commaIt = commaTokens.begin();
179       assert(parameters.size() > commaTokens.size());
180       for (; pit != pend; ++pit, ++commaIt) {
181         if (!pit->empty() && !emptyParamTermination) {
182           extendResult(result, std::move(*pit));
183         }
184         if (commaIt != commaTokens.end()) {
185           extendText(result, *commaIt);
186         } else {
187           break;
188         }
189       }
190     }
191     return;
192   }
193
194   size_t contentLength =
195     ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length;
196   auto content = cm::make_unique<GeneratorExpressionContent>(
197     startToken->Content, contentLength);
198   content->SetIdentifier(std::move(identifier));
199   content->SetParameters(std::move(parameters));
200   result.push_back(std::move(content));
201 }
202
203 void cmGeneratorExpressionParser::ParseContent(
204   cmGeneratorExpressionEvaluatorVector& result)
205 {
206   assert(this->it != this->Tokens.end());
207   switch (this->it->TokenType) {
208     case cmGeneratorExpressionToken::Text: {
209       if (this->NestingLevel == 0) {
210         if (!result.empty() &&
211             (*(result.end() - 1))->GetType() ==
212               cmGeneratorExpressionEvaluator::Text) {
213           // A comma in 'plain text' could have split text that should
214           // otherwise be continuous. Extend the last text content instead of
215           // creating a new one.
216           cm::static_reference_cast<TextContent>(*(result.end() - 1))
217             .Extend(this->it->Length);
218           assert(this->it != this->Tokens.end());
219           ++this->it;
220           return;
221         }
222       }
223       auto n =
224         cm::make_unique<TextContent>(this->it->Content, this->it->Length);
225       result.push_back(std::move(n));
226       assert(this->it != this->Tokens.end());
227       ++this->it;
228       return;
229     }
230     case cmGeneratorExpressionToken::BeginExpression:
231       assert(this->it != this->Tokens.end());
232       ++this->it;
233       this->ParseGeneratorExpression(result);
234       return;
235     case cmGeneratorExpressionToken::EndExpression:
236     case cmGeneratorExpressionToken::ColonSeparator:
237     case cmGeneratorExpressionToken::CommaSeparator:
238       if (this->NestingLevel == 0) {
239         extendText(result, this->it);
240       } else {
241         assert(false && "Got unexpected syntax token.");
242       }
243       assert(this->it != this->Tokens.end());
244       ++this->it;
245       return;
246   }
247   assert(false && "Unhandled token in generator expression.");
248 }