Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmGeneratorExpressionParser.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2012 Stephen Kelly <steveire@gmail.com>
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
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 ============================================================================*/
12
13 #include "cmGeneratorExpressionParser.h"
14
15 #include "cmGeneratorExpressionEvaluator.h"
16
17 #include "assert.h"
18
19 //----------------------------------------------------------------------------
20 cmGeneratorExpressionParser::cmGeneratorExpressionParser(
21                       const std::vector<cmGeneratorExpressionToken> &tokens)
22   : Tokens(tokens), NestingLevel(0)
23 {
24 }
25
26 //----------------------------------------------------------------------------
27 void cmGeneratorExpressionParser::Parse(
28                         std::vector<cmGeneratorExpressionEvaluator*> &result)
29 {
30   it = this->Tokens.begin();
31
32   while (this->it != this->Tokens.end())
33     {
34     this->ParseContent(result);
35     }
36 }
37
38 //----------------------------------------------------------------------------
39 static void extendText(std::vector<cmGeneratorExpressionEvaluator*> &result,
40                   std::vector<cmGeneratorExpressionToken>::const_iterator it)
41 {
42   if (result.size() > 0
43       && (*(result.end() - 1))->GetType()
44                                   == cmGeneratorExpressionEvaluator::Text)
45     {
46     TextContent *textContent = static_cast<TextContent*>(*(result.end() - 1));
47     textContent->Extend(it->Length);
48     }
49   else
50     {
51     TextContent *textContent = new TextContent(it->Content, it->Length);
52     result.push_back(textContent);
53     }
54 }
55
56 //----------------------------------------------------------------------------
57 static void extendResult(std::vector<cmGeneratorExpressionEvaluator*> &result,
58                 const std::vector<cmGeneratorExpressionEvaluator*> &contents)
59 {
60   if (result.size() > 0
61       && (*(result.end() - 1))->GetType()
62                                   == cmGeneratorExpressionEvaluator::Text
63       && (*contents.begin())->GetType()
64                                   == cmGeneratorExpressionEvaluator::Text)
65   {
66     TextContent *textContent = static_cast<TextContent*>(*(result.end() - 1));
67     textContent->Extend(
68                   static_cast<TextContent*>(*contents.begin())->GetLength());
69     delete *contents.begin();
70     result.insert(result.end(), contents.begin() + 1, contents.end());
71   } else {
72     result.insert(result.end(), contents.begin(), contents.end());
73   }
74 }
75
76 //----------------------------------------------------------------------------
77 void cmGeneratorExpressionParser::ParseGeneratorExpression(
78                         std::vector<cmGeneratorExpressionEvaluator*> &result)
79 {
80   assert(this->it != this->Tokens.end());
81   unsigned int nestedLevel = this->NestingLevel;
82   ++this->NestingLevel;
83
84   std::vector<cmGeneratorExpressionToken>::const_iterator startToken
85                                                               = this->it - 1;
86
87   std::vector<cmGeneratorExpressionEvaluator*> identifier;
88   while(this->it->TokenType != cmGeneratorExpressionToken::EndExpression
89       && this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator)
90     {
91     if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
92       {
93       extendText(identifier, this->it);
94       ++this->it;
95       }
96     else
97       {
98       this->ParseContent(identifier);
99       }
100     if (this->it == this->Tokens.end())
101       {
102       break;
103       }
104     }
105   if (identifier.empty())
106     {
107     // ERROR
108     }
109
110   if (this->it != this->Tokens.end() &&
111       this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
112     {
113     GeneratorExpressionContent *content = new GeneratorExpressionContent(
114                 startToken->Content, this->it->Content
115                                     - startToken->Content
116                                     + this->it->Length);
117     assert(this->it != this->Tokens.end());
118     ++this->it;
119     --this->NestingLevel;
120     content->SetIdentifier(identifier);
121     result.push_back(content);
122     return;
123     }
124
125   std::vector<std::vector<cmGeneratorExpressionEvaluator*> > parameters;
126   std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
127                                                             commaTokens;
128   std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
129
130   bool emptyParamTermination = false;
131
132   if (this->it != this->Tokens.end() &&
133       this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
134     {
135     colonToken = this->it;
136     parameters.resize(parameters.size() + 1);
137     assert(this->it != this->Tokens.end());
138     ++this->it;
139     if(this->it == this->Tokens.end())
140       {
141       emptyParamTermination = true;
142       }
143
144     while (this->it != this->Tokens.end() &&
145            this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
146       {
147       commaTokens.push_back(this->it);
148       parameters.resize(parameters.size() + 1);
149       assert(this->it != this->Tokens.end());
150       ++this->it;
151       if(this->it == this->Tokens.end())
152         {
153         emptyParamTermination = true;
154         }
155       }
156     while (this->it != this->Tokens.end() &&
157            this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
158       {
159       extendText(*(parameters.end() - 1), this->it);
160       assert(this->it != this->Tokens.end());
161       ++this->it;
162       }
163     while (this->it != this->Tokens.end() &&
164            this->it->TokenType != cmGeneratorExpressionToken::EndExpression)
165       {
166       this->ParseContent(*(parameters.end() - 1));
167       if (this->it == this->Tokens.end())
168         {
169         break;
170         }
171       while (this->it != this->Tokens.end() &&
172              this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
173         {
174         commaTokens.push_back(this->it);
175         parameters.resize(parameters.size() + 1);
176         assert(this->it != this->Tokens.end());
177         ++this->it;
178         if(this->it == this->Tokens.end())
179           {
180           emptyParamTermination = true;
181           }
182         }
183       while (this->it != this->Tokens.end() &&
184              this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
185         {
186         extendText(*(parameters.end() - 1), this->it);
187         assert(this->it != this->Tokens.end());
188         ++this->it;
189         }
190       }
191       if(this->it != this->Tokens.end()
192           && this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
193         {
194         --this->NestingLevel;
195         assert(this->it != this->Tokens.end());
196         ++this->it;
197         }
198     }
199
200   if (nestedLevel != this->NestingLevel)
201   {
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())
208       {
209       extendText(result, colonToken);
210
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 =
215                                                          parameters.end();
216       std::vector<TokenVector::const_iterator>::const_iterator commaIt =
217                                                          commaTokens.begin();
218       assert(parameters.size() > commaTokens.size());
219       for ( ; pit != pend; ++pit, ++commaIt)
220         {
221         if (!pit->empty() && !emptyParamTermination)
222           {
223           extendResult(result, *pit);
224           }
225         if (commaIt != commaTokens.end())
226           {
227           extendText(result, *commaIt);
228           }
229         else
230           {
231           break;
232           }
233         }
234       }
235     return;
236   }
237
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);
246 }
247
248 //----------------------------------------------------------------------------
249 void cmGeneratorExpressionParser::ParseContent(
250                         std::vector<cmGeneratorExpressionEvaluator*> &result)
251 {
252   assert(this->it != this->Tokens.end());
253   switch(this->it->TokenType)
254     {
255     case cmGeneratorExpressionToken::Text:
256     {
257       if (this->NestingLevel == 0)
258         {
259         if (result.size() > 0
260             && (*(result.end() - 1))->GetType()
261                                       == cmGeneratorExpressionEvaluator::Text)
262           {
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());
270           ++this->it;
271           return;
272           }
273         }
274       cmGeneratorExpressionEvaluator* n = new TextContent(this->it->Content,
275                                                           this->it->Length);
276       result.push_back(n);
277       assert(this->it != this->Tokens.end());
278       ++this->it;
279       return ;
280     }
281     case cmGeneratorExpressionToken::BeginExpression:
282       assert(this->it != this->Tokens.end());
283       ++this->it;
284       this->ParseGeneratorExpression(result);
285       return;
286     case cmGeneratorExpressionToken::EndExpression:
287     case cmGeneratorExpressionToken::ColonSeparator:
288     case cmGeneratorExpressionToken::CommaSeparator:
289       if (this->NestingLevel == 0)
290         {
291         extendText(result, this->it);
292         }
293       else
294         {
295           assert(!"Got unexpected syntax token.");
296         }
297       assert(this->it != this->Tokens.end());
298       ++this->it;
299       return;
300     }
301     assert(!"Unhandled token in generator expression.");
302 }