/src/CMake/Source/cmGeneratorExpressionParser.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst 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 | | #include "cmUnreachable.h" |
15 | | |
16 | | cmGeneratorExpressionParser::cmGeneratorExpressionParser( |
17 | | std::vector<cmGeneratorExpressionToken> tokens) |
18 | 26.2k | : Tokens(std::move(tokens)) |
19 | 26.2k | { |
20 | 26.2k | } |
21 | | |
22 | | void cmGeneratorExpressionParser::Parse( |
23 | | cmGeneratorExpressionEvaluatorVector& result) |
24 | 26.2k | { |
25 | 26.2k | this->it = this->Tokens.begin(); |
26 | | |
27 | 146k | while (this->it != this->Tokens.end()) { |
28 | 119k | this->ParseContent(result); |
29 | 119k | } |
30 | 26.2k | } |
31 | | |
32 | | static void extendText( |
33 | | cmGeneratorExpressionEvaluatorVector& result, |
34 | | std::vector<cmGeneratorExpressionToken>::const_iterator it) |
35 | 83.5k | { |
36 | 83.5k | if (!result.empty() && |
37 | 82.0k | (*(result.end() - 1))->GetType() == |
38 | 82.0k | cmGeneratorExpressionEvaluator::Text) { |
39 | 80.5k | cm::static_reference_cast<TextContent>(*(result.end() - 1)) |
40 | 80.5k | .Extend(it->Length); |
41 | 80.5k | } else { |
42 | 2.98k | auto textContent = cm::make_unique<TextContent>(it->Content, it->Length); |
43 | 2.98k | result.push_back(std::move(textContent)); |
44 | 2.98k | } |
45 | 83.5k | } |
46 | | |
47 | | static void extendResult( |
48 | | cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector& result, |
49 | | cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector&& contents) |
50 | 21.9k | { |
51 | 21.9k | if (!result.empty() && !contents.empty() && |
52 | 18.7k | (*(result.end() - 1))->GetType() == |
53 | 18.7k | cmGeneratorExpressionEvaluator::Text && |
54 | 18.7k | contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) { |
55 | 18.2k | cm::static_reference_cast<TextContent>(*(result.end() - 1)) |
56 | 18.2k | .Extend( |
57 | 18.2k | cm::static_reference_cast<TextContent>(contents.front()).GetLength()); |
58 | 18.2k | contents.erase(contents.begin()); |
59 | 18.2k | } |
60 | 21.9k | cm::append(result, std::move(contents)); |
61 | 21.9k | } |
62 | | |
63 | | void cmGeneratorExpressionParser::ParseGeneratorExpression( |
64 | | cmGeneratorExpressionEvaluatorVector& result) |
65 | 60.3k | { |
66 | 60.3k | assert(this->it != this->Tokens.end()); |
67 | 60.3k | unsigned int nestedLevel = this->NestingLevel; |
68 | 60.3k | ++this->NestingLevel; |
69 | | |
70 | 60.3k | auto startToken = this->it - 1; |
71 | | |
72 | 60.3k | cmGeneratorExpressionEvaluatorVector identifier; |
73 | 127k | while (this->it->TokenType != cmGeneratorExpressionToken::EndExpression && |
74 | 118k | this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator) { |
75 | 79.0k | if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) { |
76 | 1.82k | extendText(identifier, this->it); |
77 | 1.82k | ++this->it; |
78 | 77.2k | } else { |
79 | 77.2k | this->ParseContent(identifier); |
80 | 77.2k | } |
81 | 79.0k | if (this->it == this->Tokens.end()) { |
82 | 11.5k | break; |
83 | 11.5k | } |
84 | 79.0k | } |
85 | | |
86 | 60.3k | if (this->it != this->Tokens.end() && |
87 | 48.8k | this->it->TokenType == cmGeneratorExpressionToken::EndExpression) { |
88 | 9.05k | auto content = cm::make_unique<GeneratorExpressionContent>( |
89 | 9.05k | startToken->Content, |
90 | 9.05k | this->it->Content - startToken->Content + this->it->Length); |
91 | 9.05k | assert(this->it != this->Tokens.end()); |
92 | 9.05k | ++this->it; |
93 | 9.05k | --this->NestingLevel; |
94 | 9.05k | content->SetIdentifier(std::move(identifier)); |
95 | 9.05k | result.push_back(std::move(content)); |
96 | 9.05k | return; |
97 | 9.05k | } |
98 | | |
99 | 51.3k | std::vector<cmGeneratorExpressionEvaluatorVector> parameters; |
100 | 51.3k | std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator> |
101 | 51.3k | commaTokens; |
102 | 51.3k | std::vector<cmGeneratorExpressionToken>::const_iterator colonToken; |
103 | | |
104 | 51.3k | if (this->it != this->Tokens.end() && |
105 | 39.7k | this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) { |
106 | 39.7k | colonToken = this->it; |
107 | 39.7k | parameters.resize(parameters.size() + 1); |
108 | 39.7k | assert(this->it != this->Tokens.end()); |
109 | 39.7k | ++this->it; |
110 | | |
111 | 56.1k | auto handleCommaOrColon = [this, &commaTokens, ¶meters]() -> void { |
112 | 56.1k | if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) { |
113 | 33.7k | commaTokens.push_back(this->it); |
114 | 33.7k | parameters.resize(parameters.size() + 1); |
115 | 33.7k | assert(this->it != this->Tokens.end()); |
116 | 33.7k | ++this->it; |
117 | 33.7k | } else if (this->it->TokenType == |
118 | 22.3k | cmGeneratorExpressionToken::ColonSeparator) { |
119 | 22.3k | extendText(*(parameters.end() - 1), this->it); |
120 | 22.3k | assert(this->it != this->Tokens.end()); |
121 | 22.3k | ++this->it; |
122 | 22.3k | } |
123 | 56.1k | }; |
124 | | |
125 | 39.7k | while ( |
126 | 41.3k | this->it != this->Tokens.end() && |
127 | 41.3k | (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator || |
128 | 40.5k | this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)) { |
129 | 1.57k | handleCommaOrColon(); |
130 | 1.57k | } |
131 | 120k | while (this->it != this->Tokens.end() && |
132 | 120k | this->it->TokenType != cmGeneratorExpressionToken::EndExpression) { |
133 | 83.7k | this->ParseContent(*(parameters.end() - 1)); |
134 | 83.7k | if (this->it == this->Tokens.end()) { |
135 | 2.60k | break; |
136 | 2.60k | } |
137 | 81.1k | while ( |
138 | 135k | this->it != this->Tokens.end() && |
139 | 135k | (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator || |
140 | 102k | this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)) { |
141 | 54.5k | handleCommaOrColon(); |
142 | 54.5k | } |
143 | 81.1k | } |
144 | 39.7k | if (this->it != this->Tokens.end() && |
145 | 37.0k | this->it->TokenType == cmGeneratorExpressionToken::EndExpression) { |
146 | 37.0k | --this->NestingLevel; |
147 | 37.0k | assert(this->it != this->Tokens.end()); |
148 | 37.0k | ++this->it; |
149 | 37.0k | } |
150 | 39.7k | } |
151 | | |
152 | 51.3k | if (nestedLevel != this->NestingLevel) { |
153 | | // There was a '$<' in the text, but no corresponding '>'. Rebuild to |
154 | | // treat the '$<' as having been plain text, along with the |
155 | | // corresponding : and , tokens that might have been found. |
156 | 14.2k | extendText(result, startToken); |
157 | 14.2k | extendResult(result, std::move(identifier)); |
158 | 14.2k | if (!parameters.empty()) { |
159 | 2.68k | extendText(result, colonToken); |
160 | | |
161 | 2.68k | auto pit = parameters.begin(); |
162 | 2.68k | auto const pend = parameters.end(); |
163 | 2.68k | auto commaIt = commaTokens.begin(); |
164 | 2.68k | assert(parameters.size() > commaTokens.size()); |
165 | 7.68k | for (; pit != pend; ++pit, ++commaIt) { |
166 | 7.68k | extendResult(result, std::move(*pit)); |
167 | 7.68k | if (commaIt != commaTokens.end()) { |
168 | 5.00k | extendText(result, *commaIt); |
169 | 5.00k | } else { |
170 | 2.68k | break; |
171 | 2.68k | } |
172 | 7.68k | } |
173 | 2.68k | } |
174 | 14.2k | return; |
175 | 14.2k | } |
176 | | |
177 | 37.0k | size_t contentLength = |
178 | 37.0k | ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length; |
179 | 37.0k | auto content = cm::make_unique<GeneratorExpressionContent>( |
180 | 37.0k | startToken->Content, contentLength); |
181 | 37.0k | content->SetIdentifier(std::move(identifier)); |
182 | 37.0k | content->SetParameters(std::move(parameters)); |
183 | 37.0k | result.push_back(std::move(content)); |
184 | 37.0k | } |
185 | | |
186 | | void cmGeneratorExpressionParser::ParseContent( |
187 | | cmGeneratorExpressionEvaluatorVector& result) |
188 | 280k | { |
189 | 280k | assert(this->it != this->Tokens.end()); |
190 | 280k | switch (this->it->TokenType) { |
191 | 183k | case cmGeneratorExpressionToken::Text: { |
192 | 183k | if (this->NestingLevel == 0) { |
193 | 45.1k | if (!result.empty() && |
194 | 35.8k | (*(result.end() - 1))->GetType() == |
195 | 35.8k | cmGeneratorExpressionEvaluator::Text) { |
196 | | // A comma in 'plain text' could have split text that should |
197 | | // otherwise be continuous. Extend the last text content instead of |
198 | | // creating a new one. |
199 | 26.5k | cm::static_reference_cast<TextContent>(*(result.end() - 1)) |
200 | 26.5k | .Extend(this->it->Length); |
201 | 26.5k | assert(this->it != this->Tokens.end()); |
202 | 26.5k | ++this->it; |
203 | 26.5k | return; |
204 | 26.5k | } |
205 | 45.1k | } |
206 | 156k | auto n = |
207 | 156k | cm::make_unique<TextContent>(this->it->Content, this->it->Length); |
208 | 156k | result.push_back(std::move(n)); |
209 | 156k | assert(this->it != this->Tokens.end()); |
210 | 156k | ++this->it; |
211 | 156k | return; |
212 | 183k | } |
213 | 60.3k | case cmGeneratorExpressionToken::BeginExpression: |
214 | 60.3k | assert(this->it != this->Tokens.end()); |
215 | 60.3k | ++this->it; |
216 | 60.3k | if (this->it == this->Tokens.end()) { |
217 | | // A '$<' at the end of the input is plain text. |
218 | 0 | extendText(result, this->it - 1); |
219 | 0 | return; |
220 | 0 | } |
221 | 60.3k | this->ParseGeneratorExpression(result); |
222 | 60.3k | return; |
223 | 19.8k | case cmGeneratorExpressionToken::EndExpression: |
224 | 33.5k | case cmGeneratorExpressionToken::ColonSeparator: |
225 | 37.4k | case cmGeneratorExpressionToken::CommaSeparator: |
226 | 37.4k | if (this->NestingLevel == 0) { |
227 | 37.4k | extendText(result, this->it); |
228 | 37.4k | } else { |
229 | 0 | CM_UNREACHABLE; |
230 | 0 | } |
231 | 37.4k | assert(this->it != this->Tokens.end()); |
232 | 37.4k | ++this->it; |
233 | 37.4k | return; |
234 | 280k | } |
235 | 0 | CM_UNREACHABLE; |
236 | 0 | } |