blob: 83241f3c6c44c62c474e12e686f8a0e8e21ee322 [file] [log] [blame]
// Copyright 2017-2020 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "common/analysis/matcher/descent_path.h"
#include <iterator>
#include <memory>
#include <vector>
#include "common/text/concrete_syntax_tree.h"
#include "common/text/symbol.h"
namespace verible {
namespace matcher {
// AggregateAllDescendantsFromPath is a local helper for
// GetAllDescendantsFromPath. It minimizes copying by using iterators
// and pushing all discovered symbols onto a single vector.
//
// Adds all descendants of symbol that are precisely along path to target
// children must have matching SymbolTag to the last element of path.
//
// Position should point to the start position of your path and
// end should point to the end position.
//
// Discovered children are pushed back onto target
static void AggregateAllDescendantsFromPath(
const Symbol& symbol, const DescentPath::const_iterator& position,
const DescentPath::const_iterator& end, std::vector<const Symbol*>* target);
std::vector<const Symbol*> GetAllDescendantsFromPath(const Symbol& symbol,
const DescentPath& path) {
std::vector<const Symbol*> target;
if (symbol.Kind() == SymbolKind::kNode) {
const auto* node = down_cast<const SyntaxTreeNode*>(&symbol);
for (const auto& child : node->children()) {
if (child) {
AggregateAllDescendantsFromPath(*child, path.begin(), path.end(),
&target);
}
}
}
return target;
}
static void AggregateAllDescendantsFromPath(
const Symbol& symbol, const DescentPath::const_iterator& position,
const DescentPath::const_iterator& end,
std::vector<const Symbol*>* target) {
// If we are somehow operating on empty vector, stop recursion.
if (position == end) {
return;
}
// If we're at the last SymbolTag, stop recursion and check if we need to add
// symbol to target.
if (position + 1 == end) {
if (symbol.Tag() == (*position)) {
target->push_back(&symbol);
}
return;
}
// In order to recursively check descendants, symbol needs to be a node
if (symbol.Kind() != SymbolKind::kNode) {
return;
}
const auto* node = down_cast<const SyntaxTreeNode*>(&symbol);
// If the cast fails or the node does not have the required tag or kind,
// then stop recursion
const auto tag_kind = node->Tag();
if (tag_kind != *position) {
return;
}
// Recurse on children
for (const auto& child : node->children()) {
if (child) {
AggregateAllDescendantsFromPath(*child, position + 1, end, target);
}
}
}
} // namespace matcher
} // namespace verible