]> gitweb.ps.run Git - toc/blobdiff - antlr4-cpp-runtime-4.9.2-source/runtime/src/tree/xpath/XPath.cpp
add antlr source code and ReadMe
[toc] / antlr4-cpp-runtime-4.9.2-source / runtime / src / tree / xpath / XPath.cpp
diff --git a/antlr4-cpp-runtime-4.9.2-source/runtime/src/tree/xpath/XPath.cpp b/antlr4-cpp-runtime-4.9.2-source/runtime/src/tree/xpath/XPath.cpp
new file mode 100644 (file)
index 0000000..c039896
--- /dev/null
@@ -0,0 +1,154 @@
+/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+ * Use of this file is governed by the BSD 3-clause license that
+ * can be found in the LICENSE.txt file in the project root.
+ */
+
+#include "XPathLexer.h"
+#include "XPathLexerErrorListener.h"
+#include "XPathElement.h"
+#include "XPathWildcardAnywhereElement.h"
+#include "XPathWildcardElement.h"
+#include "XPathTokenAnywhereElement.h"
+#include "XPathTokenElement.h"
+#include "XPathRuleAnywhereElement.h"
+#include "XPathRuleElement.h"
+
+#include "XPath.h"
+
+using namespace antlr4;
+using namespace antlr4::tree;
+using namespace antlr4::tree::xpath;
+
+const std::string XPath::WILDCARD = "*";
+const std::string XPath::NOT = "!";
+
+XPath::XPath(Parser *parser, const std::string &path) {
+  _parser = parser;
+  _path = path;
+}
+
+std::vector<std::unique_ptr<XPathElement>> XPath::split(const std::string &path) {
+  ANTLRInputStream in(path);
+  XPathLexer lexer(&in);
+  lexer.removeErrorListeners();
+  XPathLexerErrorListener listener;
+  lexer.addErrorListener(&listener);
+  CommonTokenStream tokenStream(&lexer);
+  try {
+    tokenStream.fill();
+  } catch (LexerNoViableAltException &) {
+    size_t pos = lexer.getCharPositionInLine();
+    std::string msg = "Invalid tokens or characters at index " + std::to_string(pos) + " in path '" + path + "'";
+    throw IllegalArgumentException(msg);
+  }
+
+  std::vector<Token *> tokens = tokenStream.getTokens();
+  std::vector<std::unique_ptr<XPathElement>> elements;
+  size_t n = tokens.size();
+  size_t i = 0;
+  bool done = false;
+  while (!done && i < n) {
+    Token *el = tokens[i];
+    Token *next = nullptr;
+    switch (el->getType()) {
+      case XPathLexer::ROOT:
+      case XPathLexer::ANYWHERE: {
+        bool anywhere = el->getType() == XPathLexer::ANYWHERE;
+        i++;
+        next = tokens[i];
+        bool invert = next->getType() == XPathLexer::BANG;
+        if (invert) {
+          i++;
+          next = tokens[i];
+        }
+        std::unique_ptr<XPathElement> pathElement = getXPathElement(next, anywhere);
+        pathElement->setInvert(invert);
+        elements.push_back(std::move(pathElement));
+        i++;
+        break;
+
+      }
+      case XPathLexer::TOKEN_REF:
+      case XPathLexer::RULE_REF:
+      case XPathLexer::WILDCARD:
+        elements.push_back(getXPathElement(el, false));
+        i++;
+        break;
+
+      case Token::EOF:
+        done = true;
+        break;
+
+      default :
+        throw IllegalArgumentException("Unknown path element " + el->toString());
+    }
+  }
+
+  return elements;
+}
+
+std::unique_ptr<XPathElement> XPath::getXPathElement(Token *wordToken, bool anywhere) {
+  if (wordToken->getType() == Token::EOF) {
+    throw IllegalArgumentException("Missing path element at end of path");
+  }
+
+  std::string word = wordToken->getText();
+  size_t ttype = _parser->getTokenType(word);
+  ssize_t ruleIndex = _parser->getRuleIndex(word);
+  switch (wordToken->getType()) {
+    case XPathLexer::WILDCARD :
+      if (anywhere)
+        return std::unique_ptr<XPathWildcardAnywhereElement>(new XPathWildcardAnywhereElement());
+      return std::unique_ptr<XPathWildcardElement>(new XPathWildcardElement());
+
+    case XPathLexer::TOKEN_REF:
+    case XPathLexer::STRING :
+      if (ttype == Token::INVALID_TYPE) {
+        throw IllegalArgumentException(word + " at index " + std::to_string(wordToken->getStartIndex()) + " isn't a valid token name");
+      }
+      if (anywhere)
+        return std::unique_ptr<XPathTokenAnywhereElement>(new XPathTokenAnywhereElement(word, (int)ttype));
+      return std::unique_ptr<XPathTokenElement>(new XPathTokenElement(word, (int)ttype));
+
+    default :
+      if (ruleIndex == -1) {
+        throw IllegalArgumentException(word + " at index " + std::to_string(wordToken->getStartIndex()) + " isn't a valid rule name");
+      }
+      if (anywhere)
+        return std::unique_ptr<XPathRuleAnywhereElement>(new XPathRuleAnywhereElement(word, (int)ruleIndex));
+      return std::unique_ptr<XPathRuleElement>(new XPathRuleElement(word, (int)ruleIndex));
+  }
+}
+
+static ParserRuleContext dummyRoot;
+
+std::vector<ParseTree *> XPath::findAll(ParseTree *tree, std::string const& xpath, Parser *parser) {
+  XPath p(parser, xpath);
+  return p.evaluate(tree);
+}
+
+std::vector<ParseTree *> XPath::evaluate(ParseTree *t) {
+  dummyRoot.children = { t }; // don't set t's parent.
+
+  std::vector<ParseTree *> work = { &dummyRoot };
+
+  size_t i = 0;
+  std::vector<std::unique_ptr<XPathElement>> elements = split(_path);
+
+  while (i < elements.size()) {
+    std::vector<ParseTree *> next;
+    for (auto *node : work) {
+      if (!node->children.empty()) {
+        // only try to match next element if it has children
+        // e.g., //func/*/stat might have a token node for which
+        // we can't go looking for stat nodes.
+        auto matching = elements[i]->evaluate(node);
+        next.insert(next.end(), matching.begin(), matching.end());
+      }
+    }
+    i++;
+    work = next;
+  }
+
+  return work;
+}