cmGeneratorExpressionParser.cxx 8.51 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
3 4
#include "cmGeneratorExpressionParser.h"

5
#include "cmAlgorithms.h"
6 7
#include "cmGeneratorExpressionEvaluator.h"

8 9
#include <assert.h>
#include <stddef.h>
10
#include <utility>
11

12
cmGeneratorExpressionParser::cmGeneratorExpressionParser(
wahikihiki's avatar
wahikihiki committed
13 14
  std::vector<cmGeneratorExpressionToken> tokens)
  : Tokens(std::move(tokens))
15
  , NestingLevel(0)
16 17 18 19
{
}

void cmGeneratorExpressionParser::Parse(
20
  std::vector<cmGeneratorExpressionEvaluator*>& result)
21 22 23
{
  it = this->Tokens.begin();

24
  while (this->it != this->Tokens.end()) {
25
    this->ParseContent(result);
26
  }
27 28
}

29 30 31
static void extendText(
  std::vector<cmGeneratorExpressionEvaluator*>& result,
  std::vector<cmGeneratorExpressionToken>::const_iterator it)
32
{
33 34 35 36
  if (!result.empty() &&
      (*(result.end() - 1))->GetType() ==
        cmGeneratorExpressionEvaluator::Text) {
    TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1));
37
    textContent->Extend(it->Length);
38 39
  } else {
    TextContent* textContent = new TextContent(it->Content, it->Length);
40
    result.push_back(textContent);
41
  }
42 43
}

44 45 46
static void extendResult(
  std::vector<cmGeneratorExpressionEvaluator*>& result,
  const std::vector<cmGeneratorExpressionEvaluator*>& contents)
47
{
48 49 50
  if (!result.empty() &&
      (*(result.end() - 1))->GetType() ==
        cmGeneratorExpressionEvaluator::Text &&
51
      contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) {
52
    TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1));
53
    textContent->Extend(
54 55
      static_cast<TextContent*>(contents.front())->GetLength());
    delete contents.front();
56
    cmAppend(result, contents.begin() + 1, contents.end());
57
  } else {
58
    cmAppend(result, contents);
59 60 61 62
  }
}

void cmGeneratorExpressionParser::ParseGeneratorExpression(
63
  std::vector<cmGeneratorExpressionEvaluator*>& result)
64
{
65
  assert(this->it != this->Tokens.end());
66 67 68
  unsigned int nestedLevel = this->NestingLevel;
  ++this->NestingLevel;

69 70
  std::vector<cmGeneratorExpressionToken>::const_iterator startToken =
    this->it - 1;
71 72

  std::vector<cmGeneratorExpressionEvaluator*> identifier;
73 74 75
  while (this->it->TokenType != cmGeneratorExpressionToken::EndExpression &&
         this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator) {
    if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
76 77
      extendText(identifier, this->it);
      ++this->it;
78
    } else {
79
      this->ParseContent(identifier);
80 81
    }
    if (this->it == this->Tokens.end()) {
82 83
      break;
    }
84 85
  }
  if (identifier.empty()) {
86
    // ERROR
87
  }
88

89
  if (this->it != this->Tokens.end() &&
90
      this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
91 92 93
    GeneratorExpressionContent* content = new GeneratorExpressionContent(
      startToken->Content,
      this->it->Content - startToken->Content + this->it->Length);
94
    assert(this->it != this->Tokens.end());
95 96
    ++this->it;
    --this->NestingLevel;
97
    content->SetIdentifier(std::move(identifier));
98 99
    result.push_back(content);
    return;
100
  }
101

102
  std::vector<std::vector<cmGeneratorExpressionEvaluator*>> parameters;
103
  std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
104
    commaTokens;
105
  std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
106 107 108

  bool emptyParamTermination = false;

109
  if (this->it != this->Tokens.end() &&
110
      this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
111 112
    colonToken = this->it;
    parameters.resize(parameters.size() + 1);
113
    assert(this->it != this->Tokens.end());
114
    ++this->it;
115
    if (this->it == this->Tokens.end()) {
116
      emptyParamTermination = true;
117
    }
118 119

    while (this->it != this->Tokens.end() &&
120
           this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
121 122
      commaTokens.push_back(this->it);
      parameters.resize(parameters.size() + 1);
123
      assert(this->it != this->Tokens.end());
124
      ++this->it;
125
      if (this->it == this->Tokens.end()) {
126
        emptyParamTermination = true;
127
      }
128
    }
129
    while (this->it != this->Tokens.end() &&
130
           this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
131
      extendText(*(parameters.end() - 1), this->it);
132
      assert(this->it != this->Tokens.end());
133
      ++this->it;
134
    }
135
    while (this->it != this->Tokens.end() &&
136
           this->it->TokenType != cmGeneratorExpressionToken::EndExpression) {
137
      this->ParseContent(*(parameters.end() - 1));
138
      if (this->it == this->Tokens.end()) {
139
        break;
140
      }
141
      while (this->it != this->Tokens.end() &&
142 143
             this->it->TokenType ==
               cmGeneratorExpressionToken::CommaSeparator) {
144 145
        commaTokens.push_back(this->it);
        parameters.resize(parameters.size() + 1);
146
        assert(this->it != this->Tokens.end());
147
        ++this->it;
148
        if (this->it == this->Tokens.end()) {
149
          emptyParamTermination = true;
150
        }
151
      }
152
      while (this->it != this->Tokens.end() &&
153 154
             this->it->TokenType ==
               cmGeneratorExpressionToken::ColonSeparator) {
155
        extendText(*(parameters.end() - 1), this->it);
156
        assert(this->it != this->Tokens.end());
157
        ++this->it;
158 159
      }
    }
160 161 162 163 164 165 166
    if (this->it != this->Tokens.end() &&
        this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
      --this->NestingLevel;
      assert(this->it != this->Tokens.end());
      ++this->it;
    }
  }
167

168
  if (nestedLevel != this->NestingLevel) {
169 170 171 172 173
    // There was a '$<' in the text, but no corresponding '>'. Rebuild to
    // treat the '$<' as having been plain text, along with the
    // corresponding : and , tokens that might have been found.
    extendText(result, startToken);
    extendResult(result, identifier);
174
    if (!parameters.empty()) {
175 176 177 178 179 180
      extendText(result, colonToken);

      typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
      typedef std::vector<cmGeneratorExpressionToken> TokenVector;
      std::vector<EvaluatorVector>::const_iterator pit = parameters.begin();
      const std::vector<EvaluatorVector>::const_iterator pend =
181
        parameters.end();
182
      std::vector<TokenVector::const_iterator>::const_iterator commaIt =
183
        commaTokens.begin();
184
      assert(parameters.size() > commaTokens.size());
185 186
      for (; pit != pend; ++pit, ++commaIt) {
        if (!pit->empty() && !emptyParamTermination) {
187
          extendResult(result, *pit);
188 189
        }
        if (commaIt != commaTokens.end()) {
190
          extendText(result, *commaIt);
191
        } else {
192
          break;
193 194
        }
      }
195
    }
196 197 198
    return;
  }

199 200 201 202
  size_t contentLength =
    ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length;
  GeneratorExpressionContent* content =
    new GeneratorExpressionContent(startToken->Content, contentLength);
203 204
  content->SetIdentifier(std::move(identifier));
  content->SetParameters(std::move(parameters));
205 206 207 208
  result.push_back(content);
}

void cmGeneratorExpressionParser::ParseContent(
209
  std::vector<cmGeneratorExpressionEvaluator*>& result)
210
{
211
  assert(this->it != this->Tokens.end());
212 213 214 215 216 217
  switch (this->it->TokenType) {
    case cmGeneratorExpressionToken::Text: {
      if (this->NestingLevel == 0) {
        if (!result.empty() &&
            (*(result.end() - 1))->GetType() ==
              cmGeneratorExpressionEvaluator::Text) {
218 219 220
          // A comma in 'plain text' could have split text that should
          // otherwise be continuous. Extend the last text content instead of
          // creating a new one.
221 222
          TextContent* textContent =
            static_cast<TextContent*>(*(result.end() - 1));
223
          textContent->Extend(this->it->Length);
224
          assert(this->it != this->Tokens.end());
225 226 227
          ++this->it;
          return;
        }
228 229 230
      }
      cmGeneratorExpressionEvaluator* n =
        new TextContent(this->it->Content, this->it->Length);
231
      result.push_back(n);
232
      assert(this->it != this->Tokens.end());
233
      ++this->it;
234
      return;
235 236
    }
    case cmGeneratorExpressionToken::BeginExpression:
237
      assert(this->it != this->Tokens.end());
238 239 240 241 242 243
      ++this->it;
      this->ParseGeneratorExpression(result);
      return;
    case cmGeneratorExpressionToken::EndExpression:
    case cmGeneratorExpressionToken::ColonSeparator:
    case cmGeneratorExpressionToken::CommaSeparator:
244
      if (this->NestingLevel == 0) {
245
        extendText(result, this->it);
246
      } else {
247
        assert(false && "Got unexpected syntax token.");
248
      }
249
      assert(this->it != this->Tokens.end());
250 251
      ++this->it;
      return;
252
  }
253
  assert(false && "Unhandled token in generator expression.");
254
}