1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2012 Stephen Kelly <steveire@gmail.com>
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
13 #include "cmGeneratorExpressionParser.h"
15 #include "cmGeneratorExpressionEvaluator.h"
19 //----------------------------------------------------------------------------
20 cmGeneratorExpressionParser::cmGeneratorExpressionParser(
21 const std::vector<cmGeneratorExpressionToken> &tokens)
22 : Tokens(tokens), NestingLevel(0)
26 //----------------------------------------------------------------------------
27 void cmGeneratorExpressionParser::Parse(
28 std::vector<cmGeneratorExpressionEvaluator*> &result)
30 it = this->Tokens.begin();
32 while (this->it != this->Tokens.end())
34 this->ParseContent(result);
38 //----------------------------------------------------------------------------
39 static void extendText(std::vector<cmGeneratorExpressionEvaluator*> &result,
40 std::vector<cmGeneratorExpressionToken>::const_iterator it)
43 && (*(result.end() - 1))->GetType()
44 == cmGeneratorExpressionEvaluator::Text)
46 TextContent *textContent = static_cast<TextContent*>(*(result.end() - 1));
47 textContent->Extend(it->Length);
51 TextContent *textContent = new TextContent(it->Content, it->Length);
52 result.push_back(textContent);
56 //----------------------------------------------------------------------------
57 static void extendResult(std::vector<cmGeneratorExpressionEvaluator*> &result,
58 const std::vector<cmGeneratorExpressionEvaluator*> &contents)
61 && (*(result.end() - 1))->GetType()
62 == cmGeneratorExpressionEvaluator::Text
63 && (*contents.begin())->GetType()
64 == cmGeneratorExpressionEvaluator::Text)
66 TextContent *textContent = static_cast<TextContent*>(*(result.end() - 1));
68 static_cast<TextContent*>(*contents.begin())->GetLength());
69 delete *contents.begin();
70 result.insert(result.end(), contents.begin() + 1, contents.end());
72 result.insert(result.end(), contents.begin(), contents.end());
76 //----------------------------------------------------------------------------
77 void cmGeneratorExpressionParser::ParseGeneratorExpression(
78 std::vector<cmGeneratorExpressionEvaluator*> &result)
80 assert(this->it != this->Tokens.end());
81 unsigned int nestedLevel = this->NestingLevel;
84 std::vector<cmGeneratorExpressionToken>::const_iterator startToken
87 std::vector<cmGeneratorExpressionEvaluator*> identifier;
88 while(this->it->TokenType != cmGeneratorExpressionToken::EndExpression
89 && this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator)
91 if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
93 extendText(identifier, this->it);
98 this->ParseContent(identifier);
100 if (this->it == this->Tokens.end())
105 if (identifier.empty())
110 if (this->it != this->Tokens.end() &&
111 this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
113 GeneratorExpressionContent *content = new GeneratorExpressionContent(
114 startToken->Content, this->it->Content
115 - startToken->Content
117 assert(this->it != this->Tokens.end());
119 --this->NestingLevel;
120 content->SetIdentifier(identifier);
121 result.push_back(content);
125 std::vector<std::vector<cmGeneratorExpressionEvaluator*> > parameters;
126 std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
128 std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
129 if (this->it != this->Tokens.end() &&
130 this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
132 colonToken = this->it;
133 parameters.resize(parameters.size() + 1);
134 assert(this->it != this->Tokens.end());
137 while (this->it != this->Tokens.end() &&
138 this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
140 commaTokens.push_back(this->it);
141 parameters.resize(parameters.size() + 1);
142 assert(this->it != this->Tokens.end());
145 while (this->it != this->Tokens.end() &&
146 this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
148 extendText(*(parameters.end() - 1), this->it);
149 assert(this->it != this->Tokens.end());
152 while (this->it != this->Tokens.end() &&
153 this->it->TokenType != cmGeneratorExpressionToken::EndExpression)
155 this->ParseContent(*(parameters.end() - 1));
156 if (this->it == this->Tokens.end())
160 while (this->it != this->Tokens.end() &&
161 this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
163 commaTokens.push_back(this->it);
164 parameters.resize(parameters.size() + 1);
165 assert(this->it != this->Tokens.end());
168 while (this->it != this->Tokens.end() &&
169 this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
171 extendText(*(parameters.end() - 1), this->it);
172 assert(this->it != this->Tokens.end());
176 if(this->it != this->Tokens.end()
177 && this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
179 --this->NestingLevel;
180 assert(this->it != this->Tokens.end());
185 if (nestedLevel != this->NestingLevel)
187 // There was a '$<' in the text, but no corresponding '>'. Rebuild to
188 // treat the '$<' as having been plain text, along with the
189 // corresponding : and , tokens that might have been found.
190 extendText(result, startToken);
191 extendResult(result, identifier);
192 if (!parameters.empty())
194 extendText(result, colonToken);
196 typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
197 typedef std::vector<cmGeneratorExpressionToken> TokenVector;
198 std::vector<EvaluatorVector>::const_iterator pit = parameters.begin();
199 const std::vector<EvaluatorVector>::const_iterator pend =
201 std::vector<TokenVector::const_iterator>::const_iterator commaIt =
203 assert(parameters.size() > commaTokens.size());
204 for ( ; pit != pend; ++pit, ++commaIt)
206 extendResult(result, *pit);
207 if (commaIt != commaTokens.end())
209 extendText(result, *commaIt);
220 int contentLength = ((this->it - 1)->Content
221 - startToken->Content)
222 + (this->it - 1)->Length;
223 GeneratorExpressionContent *content = new GeneratorExpressionContent(
224 startToken->Content, contentLength);
225 content->SetIdentifier(identifier);
226 content->SetParameters(parameters);
227 result.push_back(content);
230 //----------------------------------------------------------------------------
231 void cmGeneratorExpressionParser::ParseContent(
232 std::vector<cmGeneratorExpressionEvaluator*> &result)
234 assert(this->it != this->Tokens.end());
235 switch(this->it->TokenType)
237 case cmGeneratorExpressionToken::Text:
239 if (this->NestingLevel == 0)
241 if (result.size() > 0
242 && (*(result.end() - 1))->GetType()
243 == cmGeneratorExpressionEvaluator::Text)
245 // A comma in 'plain text' could have split text that should
246 // otherwise be continuous. Extend the last text content instead of
247 // creating a new one.
248 TextContent *textContent =
249 static_cast<TextContent*>(*(result.end() - 1));
250 textContent->Extend(this->it->Length);
251 assert(this->it != this->Tokens.end());
256 cmGeneratorExpressionEvaluator* n = new TextContent(this->it->Content,
259 assert(this->it != this->Tokens.end());
263 case cmGeneratorExpressionToken::BeginExpression:
264 assert(this->it != this->Tokens.end());
266 this->ParseGeneratorExpression(result);
268 case cmGeneratorExpressionToken::EndExpression:
269 case cmGeneratorExpressionToken::ColonSeparator:
270 case cmGeneratorExpressionToken::CommaSeparator:
271 if (this->NestingLevel == 0)
273 extendText(result, this->it);
277 assert(!"Got unexpected syntax token.");
279 assert(this->it != this->Tokens.end());
283 assert(!"Unhandled token in generator expression.");