summaryrefslogtreecommitdiffstats
path: root/Source/cmGeneratorExpressionParser.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmGeneratorExpressionParser.cxx')
-rw-r--r--Source/cmGeneratorExpressionParser.cxx261
1 files changed, 261 insertions, 0 deletions
diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx
new file mode 100644
index 0000000..f853f8d
--- /dev/null
+++ b/Source/cmGeneratorExpressionParser.cxx
@@ -0,0 +1,261 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmGeneratorExpressionParser.h"
+
+#include "cmGeneratorExpressionEvaluator.h"
+
+#include "assert.h"
+
+cmGeneratorExpressionParser::cmGeneratorExpressionParser(
+ const std::vector<cmGeneratorExpressionToken>& tokens)
+ : Tokens(tokens)
+ , NestingLevel(0)
+{
+}
+
+void cmGeneratorExpressionParser::Parse(
+ std::vector<cmGeneratorExpressionEvaluator*>& result)
+{
+ it = this->Tokens.begin();
+
+ while (this->it != this->Tokens.end()) {
+ this->ParseContent(result);
+ }
+}
+
+static void extendText(
+ std::vector<cmGeneratorExpressionEvaluator*>& result,
+ std::vector<cmGeneratorExpressionToken>::const_iterator it)
+{
+ if (!result.empty() &&
+ (*(result.end() - 1))->GetType() ==
+ cmGeneratorExpressionEvaluator::Text) {
+ TextContent* textContent = static_cast<TextContent*>(*(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<cmGeneratorExpressionEvaluator*>& result,
+ const std::vector<cmGeneratorExpressionEvaluator*>& contents)
+{
+ if (!result.empty() &&
+ (*(result.end() - 1))->GetType() ==
+ cmGeneratorExpressionEvaluator::Text &&
+ (*contents.begin())->GetType() == cmGeneratorExpressionEvaluator::Text) {
+ TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1));
+ textContent->Extend(
+ static_cast<TextContent*>(*contents.begin())->GetLength());
+ delete *contents.begin();
+ result.insert(result.end(), contents.begin() + 1, contents.end());
+ } else {
+ result.insert(result.end(), contents.begin(), contents.end());
+ }
+}
+
+void cmGeneratorExpressionParser::ParseGeneratorExpression(
+ std::vector<cmGeneratorExpressionEvaluator*>& result)
+{
+ assert(this->it != this->Tokens.end());
+ unsigned int nestedLevel = this->NestingLevel;
+ ++this->NestingLevel;
+
+ std::vector<cmGeneratorExpressionToken>::const_iterator startToken =
+ this->it - 1;
+
+ std::vector<cmGeneratorExpressionEvaluator*> 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(identifier);
+ result.push_back(content);
+ return;
+ }
+
+ std::vector<std::vector<cmGeneratorExpressionEvaluator*> > 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, identifier);
+ if (!parameters.empty()) {
+ 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 =
+ parameters.end();
+ std::vector<TokenVector::const_iterator>::const_iterator 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(identifier);
+ content->SetParameters(parameters);
+ result.push_back(content);
+}
+
+void cmGeneratorExpressionParser::ParseContent(
+ std::vector<cmGeneratorExpressionEvaluator*>& 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<TextContent*>(*(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(0 && "Got unexpected syntax token.");
+ }
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ return;
+ }
+ assert(0 && "Unhandled token in generator expression.");
+}