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;
130 bool emptyParamTermination = false;
132 if (this->it != this->Tokens.end() &&
133 this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
135 colonToken = this->it;
136 parameters.resize(parameters.size() + 1);
137 assert(this->it != this->Tokens.end());
139 if(this->it == this->Tokens.end())
141 emptyParamTermination = true;
144 while (this->it != this->Tokens.end() &&
145 this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
147 commaTokens.push_back(this->it);
148 parameters.resize(parameters.size() + 1);
149 assert(this->it != this->Tokens.end());
151 if(this->it == this->Tokens.end())
153 emptyParamTermination = true;
156 while (this->it != this->Tokens.end() &&
157 this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
159 extendText(*(parameters.end() - 1), this->it);
160 assert(this->it != this->Tokens.end());
163 while (this->it != this->Tokens.end() &&
164 this->it->TokenType != cmGeneratorExpressionToken::EndExpression)
166 this->ParseContent(*(parameters.end() - 1));
167 if (this->it == this->Tokens.end())
171 while (this->it != this->Tokens.end() &&
172 this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
174 commaTokens.push_back(this->it);
175 parameters.resize(parameters.size() + 1);
176 assert(this->it != this->Tokens.end());
178 if(this->it == this->Tokens.end())
180 emptyParamTermination = true;
183 while (this->it != this->Tokens.end() &&
184 this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
186 extendText(*(parameters.end() - 1), this->it);
187 assert(this->it != this->Tokens.end());
191 if(this->it != this->Tokens.end()
192 && this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
194 --this->NestingLevel;
195 assert(this->it != this->Tokens.end());
200 if (nestedLevel != this->NestingLevel)
202 // There was a '$<' in the text, but no corresponding '>'. Rebuild to
203 // treat the '$<' as having been plain text, along with the
204 // corresponding : and , tokens that might have been found.
205 extendText(result, startToken);
206 extendResult(result, identifier);
207 if (!parameters.empty())
209 extendText(result, colonToken);
211 typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
212 typedef std::vector<cmGeneratorExpressionToken> TokenVector;
213 std::vector<EvaluatorVector>::const_iterator pit = parameters.begin();
214 const std::vector<EvaluatorVector>::const_iterator pend =
216 std::vector<TokenVector::const_iterator>::const_iterator commaIt =
218 assert(parameters.size() > commaTokens.size());
219 for ( ; pit != pend; ++pit, ++commaIt)
221 if (!pit->empty() && !emptyParamTermination)
223 extendResult(result, *pit);
225 if (commaIt != commaTokens.end())
227 extendText(result, *commaIt);
238 int contentLength = ((this->it - 1)->Content
239 - startToken->Content)
240 + (this->it - 1)->Length;
241 GeneratorExpressionContent *content = new GeneratorExpressionContent(
242 startToken->Content, contentLength);
243 content->SetIdentifier(identifier);
244 content->SetParameters(parameters);
245 result.push_back(content);
248 //----------------------------------------------------------------------------
249 void cmGeneratorExpressionParser::ParseContent(
250 std::vector<cmGeneratorExpressionEvaluator*> &result)
252 assert(this->it != this->Tokens.end());
253 switch(this->it->TokenType)
255 case cmGeneratorExpressionToken::Text:
257 if (this->NestingLevel == 0)
259 if (result.size() > 0
260 && (*(result.end() - 1))->GetType()
261 == cmGeneratorExpressionEvaluator::Text)
263 // A comma in 'plain text' could have split text that should
264 // otherwise be continuous. Extend the last text content instead of
265 // creating a new one.
266 TextContent *textContent =
267 static_cast<TextContent*>(*(result.end() - 1));
268 textContent->Extend(this->it->Length);
269 assert(this->it != this->Tokens.end());
274 cmGeneratorExpressionEvaluator* n = new TextContent(this->it->Content,
277 assert(this->it != this->Tokens.end());
281 case cmGeneratorExpressionToken::BeginExpression:
282 assert(this->it != this->Tokens.end());
284 this->ParseGeneratorExpression(result);
286 case cmGeneratorExpressionToken::EndExpression:
287 case cmGeneratorExpressionToken::ColonSeparator:
288 case cmGeneratorExpressionToken::CommaSeparator:
289 if (this->NestingLevel == 0)
291 extendText(result, this->it);
295 assert(!"Got unexpected syntax token.");
297 assert(this->it != this->Tokens.end());
301 assert(!"Unhandled token in generator expression.");