| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmGeneratorExpressionParser.h"
- #include <cassert>
- #include <cstddef>
- #include <utility>
- #include <cm/memory>
- #include <cmext/algorithm>
- #include <cmext/memory>
- #include "cmGeneratorExpressionEvaluator.h"
- cmGeneratorExpressionParser::cmGeneratorExpressionParser(
- std::vector<cmGeneratorExpressionToken> tokens)
- : Tokens(std::move(tokens))
- , NestingLevel(0)
- {
- }
- void cmGeneratorExpressionParser::Parse(
- cmGeneratorExpressionEvaluatorVector& result)
- {
- it = this->Tokens.begin();
- while (this->it != this->Tokens.end()) {
- this->ParseContent(result);
- }
- }
- static void extendText(
- cmGeneratorExpressionEvaluatorVector& result,
- std::vector<cmGeneratorExpressionToken>::const_iterator it)
- {
- if (!result.empty() &&
- (*(result.end() - 1))->GetType() ==
- cmGeneratorExpressionEvaluator::Text) {
- cm::static_reference_cast<TextContent>(*(result.end() - 1))
- .Extend(it->Length);
- } else {
- auto textContent = cm::make_unique<TextContent>(it->Content, it->Length);
- result.push_back(std::move(textContent));
- }
- }
- static void extendResult(
- cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector& result,
- cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector&& contents)
- {
- if (!result.empty() &&
- (*(result.end() - 1))->GetType() ==
- cmGeneratorExpressionEvaluator::Text &&
- contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) {
- cm::static_reference_cast<TextContent>(*(result.end() - 1))
- .Extend(
- cm::static_reference_cast<TextContent>(contents.front()).GetLength());
- contents.erase(contents.begin());
- }
- cm::append(result, std::move(contents));
- }
- void cmGeneratorExpressionParser::ParseGeneratorExpression(
- cmGeneratorExpressionEvaluatorVector& result)
- {
- assert(this->it != this->Tokens.end());
- unsigned int nestedLevel = this->NestingLevel;
- ++this->NestingLevel;
- auto startToken = this->it - 1;
- cmGeneratorExpressionEvaluatorVector identifier;
- while (this->it->TokenType != cmGeneratorExpressionToken::EndExpression &&
- this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator) {
- if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
- extendText(identifier, this->it);
- ++this->it;
- } else {
- this->ParseContent(identifier);
- }
- if (this->it == this->Tokens.end()) {
- break;
- }
- }
- if (identifier.empty()) {
- // ERROR
- }
- if (this->it != this->Tokens.end() &&
- this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
- auto content = cm::make_unique<GeneratorExpressionContent>(
- startToken->Content,
- this->it->Content - startToken->Content + this->it->Length);
- assert(this->it != this->Tokens.end());
- ++this->it;
- --this->NestingLevel;
- content->SetIdentifier(std::move(identifier));
- result.push_back(std::move(content));
- return;
- }
- std::vector<cmGeneratorExpressionEvaluatorVector> parameters;
- std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
- commaTokens;
- std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
- bool emptyParamTermination = false;
- if (this->it != this->Tokens.end() &&
- this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
- colonToken = this->it;
- parameters.resize(parameters.size() + 1);
- assert(this->it != this->Tokens.end());
- ++this->it;
- if (this->it == this->Tokens.end()) {
- emptyParamTermination = true;
- }
- while (this->it != this->Tokens.end() &&
- this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
- commaTokens.push_back(this->it);
- parameters.resize(parameters.size() + 1);
- assert(this->it != this->Tokens.end());
- ++this->it;
- if (this->it == this->Tokens.end()) {
- emptyParamTermination = true;
- }
- }
- while (this->it != this->Tokens.end() &&
- this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
- extendText(*(parameters.end() - 1), this->it);
- assert(this->it != this->Tokens.end());
- ++this->it;
- }
- while (this->it != this->Tokens.end() &&
- this->it->TokenType != cmGeneratorExpressionToken::EndExpression) {
- this->ParseContent(*(parameters.end() - 1));
- if (this->it == this->Tokens.end()) {
- break;
- }
- while (this->it != this->Tokens.end() &&
- this->it->TokenType ==
- cmGeneratorExpressionToken::CommaSeparator) {
- commaTokens.push_back(this->it);
- parameters.resize(parameters.size() + 1);
- assert(this->it != this->Tokens.end());
- ++this->it;
- if (this->it == this->Tokens.end()) {
- emptyParamTermination = true;
- }
- }
- while (this->it != this->Tokens.end() &&
- this->it->TokenType ==
- cmGeneratorExpressionToken::ColonSeparator) {
- extendText(*(parameters.end() - 1), this->it);
- assert(this->it != this->Tokens.end());
- ++this->it;
- }
- }
- if (this->it != this->Tokens.end() &&
- this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
- --this->NestingLevel;
- assert(this->it != this->Tokens.end());
- ++this->it;
- }
- }
- if (nestedLevel != this->NestingLevel) {
- // 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, std::move(identifier));
- if (!parameters.empty()) {
- extendText(result, colonToken);
- auto pit = parameters.begin();
- const auto pend = parameters.end();
- auto commaIt = commaTokens.begin();
- assert(parameters.size() > commaTokens.size());
- for (; pit != pend; ++pit, ++commaIt) {
- if (!pit->empty() && !emptyParamTermination) {
- extendResult(result, std::move(*pit));
- }
- if (commaIt != commaTokens.end()) {
- extendText(result, *commaIt);
- } else {
- break;
- }
- }
- }
- return;
- }
- size_t contentLength =
- ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length;
- auto content = cm::make_unique<GeneratorExpressionContent>(
- startToken->Content, contentLength);
- content->SetIdentifier(std::move(identifier));
- content->SetParameters(std::move(parameters));
- result.push_back(std::move(content));
- }
- void cmGeneratorExpressionParser::ParseContent(
- cmGeneratorExpressionEvaluatorVector& result)
- {
- assert(this->it != this->Tokens.end());
- switch (this->it->TokenType) {
- case cmGeneratorExpressionToken::Text: {
- if (this->NestingLevel == 0) {
- if (!result.empty() &&
- (*(result.end() - 1))->GetType() ==
- cmGeneratorExpressionEvaluator::Text) {
- // 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.
- cm::static_reference_cast<TextContent>(*(result.end() - 1))
- .Extend(this->it->Length);
- assert(this->it != this->Tokens.end());
- ++this->it;
- return;
- }
- }
- auto n =
- cm::make_unique<TextContent>(this->it->Content, this->it->Length);
- result.push_back(std::move(n));
- assert(this->it != this->Tokens.end());
- ++this->it;
- return;
- }
- case cmGeneratorExpressionToken::BeginExpression:
- assert(this->it != this->Tokens.end());
- ++this->it;
- this->ParseGeneratorExpression(result);
- return;
- case cmGeneratorExpressionToken::EndExpression:
- case cmGeneratorExpressionToken::ColonSeparator:
- case cmGeneratorExpressionToken::CommaSeparator:
- if (this->NestingLevel == 0) {
- extendText(result, this->it);
- } else {
- assert(false && "Got unexpected syntax token.");
- }
- assert(this->it != this->Tokens.end());
- ++this->it;
- return;
- }
- assert(false && "Unhandled token in generator expression.");
- }
|