| // 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 |