blob: 3f005ad6f5d9acff32e1b27424269b5083ba08ff [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/matcher.h"
#include <memory>
#include <vector>
#include "common/analysis/matcher/bound_symbol_manager.h"
#include "common/analysis/matcher/inner_match_handlers.h"
#include "common/analysis/matcher/matcher_builders.h"
#include "common/text/concrete_syntax_leaf.h"
#include "common/text/concrete_syntax_tree.h"
#include "common/text/symbol.h"
#include "common/text/tree_builder_test_util.h"
#include "gtest/gtest.h"
namespace verible {
namespace matcher {
namespace {
TEST(MatcherTest, SimpleNonNestedMatchers) {
auto matcher =
Matcher(EqualTagPredicate<SymbolKind::kNode, int, 5>, InnerMatchAll);
BoundSymbolManager bound_symbol_manager;
const auto should_match = TNode(5);
EXPECT_TRUE(matcher.Matches(*should_match, &bound_symbol_manager));
const auto no_match = TNode(6);
EXPECT_FALSE(matcher.Matches(*no_match, &bound_symbol_manager));
}
TEST(MatcherTest, SimpleNestedMatchersSuccess) {
auto inner_matcher =
Matcher(EqualTagPredicate<SymbolKind::kNode, int, 5>, InnerMatchAll);
auto outer_matcher =
Matcher(EqualTagPredicate<SymbolKind::kNode, int, 5>, InnerMatchAll);
outer_matcher.AddMatchers(inner_matcher);
BoundSymbolManager bound_symbol_manager;
const auto should_match = TNode(5);
EXPECT_TRUE(outer_matcher.Matches(*should_match, &bound_symbol_manager));
const auto no_match = TNode(6);
EXPECT_FALSE(outer_matcher.Matches(*no_match, &bound_symbol_manager));
}
TEST(MatcherTest, SimpleNestedMatchersFailure) {
auto inner_matcher =
Matcher(EqualTagPredicate<SymbolKind::kNode, int, 6>, InnerMatchAll);
auto outer_matcher =
Matcher(EqualTagPredicate<SymbolKind::kNode, int, 5>, InnerMatchAll);
outer_matcher.AddMatchers(inner_matcher);
BoundSymbolManager bound_symbol_manager;
const auto no_match1 = TNode(5);
EXPECT_FALSE(outer_matcher.Matches(*no_match1, &bound_symbol_manager));
const auto no_match2 = TNode(6);
EXPECT_FALSE(outer_matcher.Matches(*no_match2, &bound_symbol_manager));
}
TEST(MatcherTest, MatchAnyNested) {
auto inner_matcher1 =
Matcher(EqualTagPredicate<SymbolKind::kNode, int, 5>, InnerMatchAll);
auto inner_matcher2 =
Matcher(EqualTagPredicate<SymbolKind::kNode, int, 6>, InnerMatchAll);
auto outer_matcher =
Matcher(EqualTagPredicate<SymbolKind::kNode, int, 5>, InnerMatchAny);
outer_matcher.AddMatchers(inner_matcher1, inner_matcher2);
BoundSymbolManager bound_symbol_manager;
const auto should_match = TNode(5);
EXPECT_TRUE(outer_matcher.Matches(*should_match, &bound_symbol_manager));
const auto no_match = TNode(6);
EXPECT_FALSE(outer_matcher.Matches(*no_match, &bound_symbol_manager));
}
TEST(MatcherTest, BindMatcherFlat) {
auto matcher = BindableMatcher(EqualTagPredicate<SymbolKind::kNode, int, 5>,
InnerMatchAll)
.Bind("f");
BoundSymbolManager bound_symbol_manager;
const auto should_match = TNode(5);
EXPECT_TRUE(matcher.Matches(*should_match, &bound_symbol_manager));
EXPECT_TRUE(bound_symbol_manager.ContainsSymbol("f"));
const auto* node_ptr =
down_cast<const SyntaxTreeNode*>(bound_symbol_manager.FindSymbol("f"));
ASSERT_NE(node_ptr, nullptr);
EXPECT_TRUE(node_ptr->MatchesTag(5));
EXPECT_EQ(bound_symbol_manager.Size(), 1);
bound_symbol_manager.Clear();
const auto no_match = TNode(6);
EXPECT_FALSE(matcher.Matches(*no_match, &bound_symbol_manager));
EXPECT_FALSE(bound_symbol_manager.ContainsSymbol("f"));
EXPECT_EQ(bound_symbol_manager.Size(), 0);
}
TEST(MatcherTest, BindMatcherNested) {
auto outer_matcher =
BindableMatcher(EqualTagPredicate<SymbolKind::kNode, int, 5>,
InnerMatchAll)
.Bind("f");
auto inner_matcher =
BindableMatcher(EqualTagPredicate<SymbolKind::kNode, int, 5>,
InnerMatchAll)
.Bind("g");
outer_matcher.AddMatchers(inner_matcher);
BoundSymbolManager bound_symbol_manager;
auto should_match = TNode(5);
EXPECT_TRUE(outer_matcher.Matches(*should_match, &bound_symbol_manager));
EXPECT_TRUE(bound_symbol_manager.ContainsSymbol("f"));
EXPECT_TRUE(bound_symbol_manager.ContainsSymbol("g"));
const auto* outer_match =
down_cast<const SyntaxTreeNode*>(bound_symbol_manager.FindSymbol("f"));
auto inner_match =
down_cast<const SyntaxTreeNode*>(bound_symbol_manager.FindSymbol("g"));
ASSERT_NE(outer_match, nullptr);
ASSERT_NE(inner_match, nullptr);
EXPECT_TRUE(inner_match->MatchesTag(5));
EXPECT_TRUE(outer_match->MatchesTag(5));
EXPECT_EQ(bound_symbol_manager.Size(), 2);
bound_symbol_manager.Clear();
auto no_match = TNode(6);
EXPECT_FALSE(outer_matcher.Matches(*no_match, &bound_symbol_manager));
EXPECT_FALSE(bound_symbol_manager.ContainsSymbol("f"));
EXPECT_FALSE(bound_symbol_manager.ContainsSymbol("g"));
EXPECT_EQ(bound_symbol_manager.Size(), 0);
}
// Returns first child of symbol as a one element array.
// If symbol is a leaf or doesn't have children, returns empty array.
static std::vector<const Symbol*> GetFirstChild(const Symbol& symbol) {
if (symbol.Kind() == SymbolKind::kNode) {
const auto& node = down_cast<const SyntaxTreeNode&>(symbol);
if (node.children().empty()) {
return {};
} else {
return {node.children()[0].get()};
}
}
return {};
}
static bool HasExactlyOneChild(const Symbol& symbol) {
return GetFirstChild(symbol).size() == 1;
}
TEST(MatcherTest, SimpleTransformerTest) {
auto outer_matcher =
BindableMatcher(EqualTagPredicate<SymbolKind::kNode, int, 5>,
InnerMatchAll)
.Bind("f");
auto inner_matcher =
BindableMatcher(HasExactlyOneChild, InnerMatchAll, GetFirstChild)
.Bind("g");
outer_matcher.AddMatchers(inner_matcher);
BoundSymbolManager bound_symbol_manager;
auto should_match = TNode(5, XLeaf(123));
EXPECT_TRUE(outer_matcher.Matches(*should_match, &bound_symbol_manager));
EXPECT_TRUE(bound_symbol_manager.ContainsSymbol("f"));
EXPECT_TRUE(bound_symbol_manager.ContainsSymbol("g"));
const auto* outer_match =
down_cast<const SyntaxTreeNode*>(bound_symbol_manager.FindSymbol("f"));
const auto* inner_match =
down_cast<const SyntaxTreeLeaf*>(bound_symbol_manager.FindSymbol("g"));
ASSERT_NE(outer_match, nullptr);
ASSERT_NE(inner_match, nullptr);
EXPECT_EQ(outer_match->Tag(), NodeTag(5));
EXPECT_EQ(inner_match->Tag(), LeafTag(123));
}
} // namespace
} // namespace matcher
} // namespace verible