| // 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. | |
| #ifndef VERIBLE_COMMON_ANALYSIS_MATCHER_MATCHER_H_ | |
| #define VERIBLE_COMMON_ANALYSIS_MATCHER_MATCHER_H_ | |
| #include <functional> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include "absl/types/optional.h" | |
| #include "common/analysis/matcher/bound_symbol_manager.h" | |
| #include "common/text/symbol.h" | |
| namespace verible { | |
| namespace matcher { | |
| // Forward declaration of Matcher class | |
| class Matcher; | |
| using SymbolPredicate = std::function<bool(const Symbol&)>; | |
| using SymbolTransformer = | |
| std::function<std::vector<const Symbol*>(const Symbol&)>; | |
| // Manages recursion on symbol for inner_matchers | |
| using InnerMatchHandler = std::function<bool( | |
| const Symbol& symbol, const std::vector<Matcher>& inner_matchers, | |
| BoundSymbolManager* manager)>; | |
| // Matcher provides an interface for creating nested tree pattern matchers. | |
| // | |
| // Usage: | |
| // Matcher matcher(some_symbol_predicate, some_match_handler); | |
| // matcher.AddMatchers(... some children matchers ...); | |
| // | |
| // BoundSymbolManager manager; | |
| // | |
| // matcher.Matches(...some node..., &manager); | |
| // | |
| // Modeled after Clang ASTMatcher's Matcher class | |
| // See ASTMatchersInternal.h, class Matcher | |
| // | |
| class Matcher { | |
| public: | |
| Matcher(const SymbolPredicate& p, const InnerMatchHandler& handler) | |
| : predicate_(p), inner_match_handler_(handler) {} | |
| Matcher(const SymbolPredicate& p, const InnerMatchHandler& handler, | |
| const SymbolTransformer& t) | |
| : predicate_(p), inner_match_handler_(handler), transformer_(t) {} | |
| // Returns true if this and all submatchers match on symbol. | |
| // Returns false otherwise. | |
| // If this and all submatchers match, adds their bound symbols to manager | |
| // If bind_id_ is not nullopt, then bind symbol to bind_id_ | |
| // TODO(jeremycs): implement match branching behavior here. | |
| bool Matches(const Symbol& symbol, BoundSymbolManager* manager) const; | |
| // No-op case for variadic AddMatcher. | |
| void AddMatchers() const {} | |
| // Adds an arbitrary number of matchers to this as submatchers | |
| template <typename... Args> | |
| void AddMatchers(const Matcher& matcher, Args&&... args) { | |
| inner_matchers_.push_back(matcher); | |
| AddMatchers(std::forward<Args>(args)...); | |
| } | |
| private: | |
| // Contains all inner matchers. | |
| std::vector<Matcher> inner_matchers_; | |
| protected: | |
| // Determines whether or not this matches against a given symbol. | |
| SymbolPredicate predicate_; | |
| // Define the recursion strategy that is used for traversing inner matchers. | |
| InnerMatchHandler inner_match_handler_; | |
| // This transformation is applied to a matched symbol before it is passed | |
| // to inner matchers. | |
| // Default transformation does not modify symbol. | |
| SymbolTransformer transformer_ = | |
| [](const Symbol& symbol) -> std::vector<const Symbol*> { | |
| return {&symbol}; | |
| }; | |
| // If present when Matches is called, symbol will be bound to its value | |
| // If null_opt, then symbol will not be | |
| absl::optional<std::string> bind_id_ = absl::nullopt; | |
| }; | |
| // BindableMatcher is a subclass of matcher that enables setting | |
| // bind_id_. | |
| // | |
| // This class allows the accompanying DSL to restrict which matchers are | |
| // allowed to bind symbols. | |
| // | |
| // bind_id_ should not be allowed to be set in the general case. This is | |
| // because there are many types matchers for which binding to an id does not | |
| // make sense. For instance, AnyOf/AllOf. | |
| // | |
| // Usage: | |
| // auto matcher = Matcher(some_symbol_predicate, | |
| // some_match_handler).Bind("my-id") | |
| // BoundSymbolManager manager; | |
| // bool matched = matcher.Matches(...some node..., &manager); | |
| // | |
| // If matched is true, then manager will contain a node bound to "my-id" | |
| // | |
| class BindableMatcher : public Matcher { | |
| public: | |
| // Inherit constructors from Matcher | |
| using Matcher::Matcher; | |
| BindableMatcher& Bind(const std::string& id) { | |
| bind_id_ = id; | |
| return *this; | |
| } | |
| }; | |
| } // namespace matcher | |
| } // namespace verible | |
| #endif // VERIBLE_COMMON_ANALYSIS_MATCHER_MATCHER_H_ |