X-Git-Url: https://gitweb.ps.run/toc/blobdiff_plain/9f94b672a5dc32da5ad01742bd4e976315a30d9c..c6ad2948bb98d42f8e0883ef82cd14cd2d5eda60:/antlr4-cpp-runtime-4.9.2-source/runtime/src/tree/Trees.cpp diff --git a/antlr4-cpp-runtime-4.9.2-source/runtime/src/tree/Trees.cpp b/antlr4-cpp-runtime-4.9.2-source/runtime/src/tree/Trees.cpp new file mode 100644 index 0000000..34cfb74 --- /dev/null +++ b/antlr4-cpp-runtime-4.9.2-source/runtime/src/tree/Trees.cpp @@ -0,0 +1,241 @@ +/* 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 "tree/ErrorNode.h" +#include "Parser.h" +#include "ParserRuleContext.h" +#include "support/CPPUtils.h" +#include "tree/TerminalNodeImpl.h" +#include "atn/ATN.h" +#include "misc/Interval.h" +#include "Token.h" +#include "CommonToken.h" +#include "misc/Predicate.h" + +#include "tree/Trees.h" + +using namespace antlr4; +using namespace antlr4::misc; +using namespace antlr4::tree; + +using namespace antlrcpp; + +Trees::Trees() { +} + +std::string Trees::toStringTree(ParseTree *t, bool pretty) { + return toStringTree(t, nullptr, pretty); +} + +std::string Trees::toStringTree(ParseTree *t, Parser *recog, bool pretty) { + if (recog == nullptr) + return toStringTree(t, std::vector(), pretty); + return toStringTree(t, recog->getRuleNames(), pretty); +} + +std::string Trees::toStringTree(ParseTree *t, const std::vector &ruleNames, bool pretty) { + std::string temp = antlrcpp::escapeWhitespace(Trees::getNodeText(t, ruleNames), false); + if (t->children.empty()) { + return temp; + } + + std::stringstream ss; + ss << "(" << temp << ' '; + + // Implement the recursive walk as iteration to avoid trouble with deep nesting. + std::stack stack; + size_t childIndex = 0; + ParseTree *run = t; + size_t indentationLevel = 1; + while (childIndex < run->children.size()) { + if (childIndex > 0) { + ss << ' '; + } + ParseTree *child = run->children[childIndex]; + temp = antlrcpp::escapeWhitespace(Trees::getNodeText(child, ruleNames), false); + if (!child->children.empty()) { + // Go deeper one level. + stack.push(childIndex); + run = child; + childIndex = 0; + if (pretty) { + ++indentationLevel; + ss << std::endl; + for (size_t i = 0; i < indentationLevel; ++i) { + ss << " "; + } + } + ss << "(" << temp << " "; + } else { + ss << temp; + while (++childIndex == run->children.size()) { + if (stack.size() > 0) { + // Reached the end of the current level. See if we can step up from here. + childIndex = stack.top(); + stack.pop(); + run = run->parent; + if (pretty) { + --indentationLevel; + } + ss << ")"; + } else { + break; + } + } + } + } + + ss << ")"; + return ss.str(); +} + +std::string Trees::getNodeText(ParseTree *t, Parser *recog) { + return getNodeText(t, recog->getRuleNames()); +} + +std::string Trees::getNodeText(ParseTree *t, const std::vector &ruleNames) { + if (ruleNames.size() > 0) { + if (is(t)) { + size_t ruleIndex = dynamic_cast(t)->getRuleIndex(); + std::string ruleName = ruleNames[ruleIndex]; + size_t altNumber = dynamic_cast(t)->getAltNumber(); + if (altNumber != atn::ATN::INVALID_ALT_NUMBER) { + return ruleName + ":" + std::to_string(altNumber); + } + return ruleName; + } else if (is(t)) { + return t->toString(); + } else if (is(t)) { + Token *symbol = dynamic_cast(t)->getSymbol(); + if (symbol != nullptr) { + std::string s = symbol->getText(); + return s; + } + } + } + // no recog for rule names + if (is(t)) { + return dynamic_cast(t)->getText(); + } + + if (is(t)) { + return dynamic_cast(t)->getSymbol()->getText(); + } + + return ""; +} + +std::vector Trees::getAncestors(ParseTree *t) { + std::vector ancestors; + ParseTree *parent = t->parent; + while (parent != nullptr) { + ancestors.insert(ancestors.begin(), parent); // insert at start + parent = parent->parent; + } + return ancestors; +} + +template +static void _findAllNodes(ParseTree *t, size_t index, bool findTokens, std::vector &nodes) { + // check this node (the root) first + if (findTokens && is(t)) { + TerminalNode *tnode = dynamic_cast(t); + if (tnode->getSymbol()->getType() == index) { + nodes.push_back(t); + } + } else if (!findTokens && is(t)) { + ParserRuleContext *ctx = dynamic_cast(t); + if (ctx->getRuleIndex() == index) { + nodes.push_back(t); + } + } + // check children + for (size_t i = 0; i < t->children.size(); i++) { + _findAllNodes(t->children[i], index, findTokens, nodes); + } +} + +bool Trees::isAncestorOf(ParseTree *t, ParseTree *u) { + if (t == nullptr || u == nullptr || t->parent == nullptr) { + return false; + } + + ParseTree *p = u->parent; + while (p != nullptr) { + if (t == p) { + return true; + } + p = p->parent; + } + return false; +} + +std::vector Trees::findAllTokenNodes(ParseTree *t, size_t ttype) { + return findAllNodes(t, ttype, true); +} + +std::vector Trees::findAllRuleNodes(ParseTree *t, size_t ruleIndex) { + return findAllNodes(t, ruleIndex, false); +} + +std::vector Trees::findAllNodes(ParseTree *t, size_t index, bool findTokens) { + std::vector nodes; + _findAllNodes(t, index, findTokens, nodes); + return nodes; +} + +std::vector Trees::getDescendants(ParseTree *t) { + std::vector nodes; + nodes.push_back(t); + std::size_t n = t->children.size(); + for (size_t i = 0 ; i < n ; i++) { + auto descentants = getDescendants(t->children[i]); + for (auto *entry: descentants) { + nodes.push_back(entry); + } + } + return nodes; +} + +std::vector Trees::descendants(ParseTree *t) { + return getDescendants(t); +} + +ParserRuleContext* Trees::getRootOfSubtreeEnclosingRegion(ParseTree *t, size_t startTokenIndex, size_t stopTokenIndex) { + size_t n = t->children.size(); + for (size_t i = 0; i < n; i++) { + ParserRuleContext *r = getRootOfSubtreeEnclosingRegion(t->children[i], startTokenIndex, stopTokenIndex); + if (r != nullptr) { + return r; + } + } + + if (is(t)) { + ParserRuleContext *r = dynamic_cast(t); + if (startTokenIndex >= r->getStart()->getTokenIndex() && // is range fully contained in t? + (r->getStop() == nullptr || stopTokenIndex <= r->getStop()->getTokenIndex())) { + // note: r.getStop()==null likely implies that we bailed out of parser and there's nothing to the right + return r; + } + } + return nullptr; +} + +ParseTree * Trees::findNodeSuchThat(ParseTree *t, Ref const& pred) { + if (pred->test(t)) { + return t; + } + + size_t n = t->children.size(); + for (size_t i = 0 ; i < n ; ++i) { + ParseTree *u = findNodeSuchThat(t->children[i], pred); + if (u != nullptr) { + return u; + } + } + + return nullptr; +} +