Imported Upstream version 2.8.11.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   if (this->it != this->Tokens.end() &&
130       this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
131     {
132     colonToken = this->it;
133     parameters.resize(parameters.size() + 1);
134     assert(this->it != this->Tokens.end());
135     ++this->it;
136
137     while (this->it != this->Tokens.end() &&
138            this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
139       {
140       commaTokens.push_back(this->it);
141       parameters.resize(parameters.size() + 1);
142       assert(this->it != this->Tokens.end());
143       ++this->it;
144       }
145     while (this->it != this->Tokens.end() &&
146            this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
147       {
148       extendText(*(parameters.end() - 1), this->it);
149       assert(this->it != this->Tokens.end());
150       ++this->it;
151       }
152     while (this->it != this->Tokens.end() &&
153            this->it->TokenType != cmGeneratorExpressionToken::EndExpression)
154       {
155       this->ParseContent(*(parameters.end() - 1));
156       if (this->it == this->Tokens.end())
157         {
158         break;
159         }
160       while (this->it != this->Tokens.end() &&
161              this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
162         {
163         commaTokens.push_back(this->it);
164         parameters.resize(parameters.size() + 1);
165         assert(this->it != this->Tokens.end());
166         ++this->it;
167         }
168       while (this->it != this->Tokens.end() &&
169              this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
170         {
171         extendText(*(parameters.end() - 1), this->it);
172         assert(this->it != this->Tokens.end());
173         ++this->it;
174         }
175       }
176       if(this->it != this->Tokens.end()
177           && this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
178         {
179         --this->NestingLevel;
180         assert(this->it != this->Tokens.end());
181         ++this->it;
182         }
183     }
184
185   if (nestedLevel != this->NestingLevel)
186   {
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())
193       {
194       extendText(result, colonToken);
195
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 =
200                                                          parameters.end();
201       std::vector<TokenVector::const_iterator>::const_iterator commaIt =
202                                                          commaTokens.begin();
203       assert(parameters.size() > commaTokens.size());
204       for ( ; pit != pend; ++pit, ++commaIt)
205         {
206         extendResult(result, *pit);
207         if (commaIt != commaTokens.end())
208           {
209           extendText(result, *commaIt);
210           }
211         else
212           {
213           break;
214           }
215         }
216       }
217     return;
218   }
219
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);
228 }
229
230 //----------------------------------------------------------------------------
231 void cmGeneratorExpressionParser::ParseContent(
232                         std::vector<cmGeneratorExpressionEvaluator*> &result)
233 {
234   assert(this->it != this->Tokens.end());
235   switch(this->it->TokenType)
236     {
237     case cmGeneratorExpressionToken::Text:
238     {
239       if (this->NestingLevel == 0)
240         {
241         if (result.size() > 0
242             && (*(result.end() - 1))->GetType()
243                                       == cmGeneratorExpressionEvaluator::Text)
244           {
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());
252           ++this->it;
253           return;
254           }
255         }
256       cmGeneratorExpressionEvaluator* n = new TextContent(this->it->Content,
257                                                           this->it->Length);
258       result.push_back(n);
259       assert(this->it != this->Tokens.end());
260       ++this->it;
261       return ;
262     }
263     case cmGeneratorExpressionToken::BeginExpression:
264       assert(this->it != this->Tokens.end());
265       ++this->it;
266       this->ParseGeneratorExpression(result);
267       return;
268     case cmGeneratorExpressionToken::EndExpression:
269     case cmGeneratorExpressionToken::ColonSeparator:
270     case cmGeneratorExpressionToken::CommaSeparator:
271       if (this->NestingLevel == 0)
272         {
273         extendText(result, this->it);
274         }
275       else
276         {
277           assert(!"Got unexpected syntax token.");
278         }
279       assert(this->it != this->Tokens.end());
280       ++this->it;
281       return;
282     }
283     assert(!"Unhandled token in generator expression.");
284 }