/* 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; }