/* 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 "cmAlgorithms.h" #include "cmGeneratorExpressionEvaluator.h" #include #include #include cmGeneratorExpressionParser::cmGeneratorExpressionParser( std::vector tokens) : Tokens(std::move(tokens)) , NestingLevel(0) { } void cmGeneratorExpressionParser::Parse( std::vector& result) { it = this->Tokens.begin(); while (this->it != this->Tokens.end()) { this->ParseContent(result); } } static void extendText( std::vector& result, std::vector::const_iterator it) { if (!result.empty() && (*(result.end() - 1))->GetType() == cmGeneratorExpressionEvaluator::Text) { TextContent* textContent = static_cast(*(result.end() - 1)); textContent->Extend(it->Length); } else { TextContent* textContent = new TextContent(it->Content, it->Length); result.push_back(textContent); } } static void extendResult( std::vector& result, const std::vector& contents) { if (!result.empty() && (*(result.end() - 1))->GetType() == cmGeneratorExpressionEvaluator::Text && contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) { TextContent* textContent = static_cast(*(result.end() - 1)); textContent->Extend( static_cast(contents.front())->GetLength()); delete contents.front(); cmAppend(result, contents.begin() + 1, contents.end()); } else { cmAppend(result, contents); } } void cmGeneratorExpressionParser::ParseGeneratorExpression( std::vector& result) { assert(this->it != this->Tokens.end()); unsigned int nestedLevel = this->NestingLevel; ++this->NestingLevel; auto startToken = this->it - 1; std::vector 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) { GeneratorExpressionContent* content = new 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(content); return; } std::vector> parameters; std::vector::const_iterator> commaTokens; std::vector::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, 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, *pit); } if (commaIt != commaTokens.end()) { extendText(result, *commaIt); } else { break; } } } return; } size_t contentLength = ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length; GeneratorExpressionContent* content = new GeneratorExpressionContent(startToken->Content, contentLength); content->SetIdentifier(std::move(identifier)); content->SetParameters(std::move(parameters)); result.push_back(content); } void cmGeneratorExpressionParser::ParseContent( std::vector& 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. TextContent* textContent = static_cast(*(result.end() - 1)); textContent->Extend(this->it->Length); assert(this->it != this->Tokens.end()); ++this->it; return; } } cmGeneratorExpressionEvaluator* n = new TextContent(this->it->Content, this->it->Length); result.push_back(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."); }