| // 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/text/syntax_tree_context.h" |
| |
| #include "common/text/concrete_syntax_tree.h" |
| #include "common/util/iterator_range.h" |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| |
| namespace verible { |
| namespace { |
| |
| using ::testing::ElementsAre; |
| |
| // Test that AutoPop properly pushes and pops nodes on and off the stack |
| TEST(SyntaxTreeContextTest, PushPopTest) { |
| SyntaxTreeContext context; |
| const auto& const_context = context; |
| EXPECT_TRUE(context.empty()); |
| { |
| SyntaxTreeNode node1(1); |
| SyntaxTreeContext::AutoPop p1(&context, &node1); |
| EXPECT_EQ(&const_context.top(), &node1); |
| } |
| EXPECT_TRUE(context.empty()); |
| SyntaxTreeNode node2(2); |
| SyntaxTreeContext::AutoPop p2(&context, &node2); |
| SyntaxTreeNode node3(3); |
| SyntaxTreeNode node4(4); |
| { |
| SyntaxTreeContext::AutoPop p3(&context, &node3); |
| EXPECT_EQ(&const_context.top(), &node3); |
| SyntaxTreeContext::AutoPop p4(&context, &node4); |
| EXPECT_EQ(&const_context.top(), &node4); |
| } |
| EXPECT_EQ(&const_context.top(), &node2); |
| } |
| |
| // Test that forward/reverse iterators correctly look down/up the stack. |
| TEST(SyntaxTreeContextTest, IteratorsTest) { |
| SyntaxTreeContext context; |
| { |
| SyntaxTreeNode node1(1); |
| SyntaxTreeContext::AutoPop p1(&context, &node1); |
| { |
| SyntaxTreeNode node2(2); |
| SyntaxTreeContext::AutoPop p2(&context, &node2); |
| { |
| SyntaxTreeNode node3(3); |
| SyntaxTreeContext::AutoPop p3(&context, &node3); |
| |
| EXPECT_THAT(verible::make_range(context.begin(), context.end()), |
| ElementsAre(&node1, &node2, &node3)); |
| EXPECT_THAT(verible::make_range(context.rbegin(), context.rend()), |
| ElementsAre(&node3, &node2, &node1)); |
| } |
| } |
| } |
| } |
| |
| // Test that IsInside and IsInsideStartingFrom correctly reports whether |
| // context matches. |
| TEST(SyntaxTreeContextTest, IsInsideTest) { |
| SyntaxTreeContext context; |
| EXPECT_FALSE(context.IsInside(1)); |
| EXPECT_FALSE(context.IsInside(2)); |
| EXPECT_FALSE(context.IsInside(3)); |
| EXPECT_FALSE(context.IsInsideStartingFrom(1, 1)); |
| EXPECT_FALSE(context.IsInsideStartingFrom(1, 0)); |
| { |
| SyntaxTreeNode node1(1); |
| SyntaxTreeContext::AutoPop p1(&context, &node1); |
| EXPECT_TRUE(context.IsInside(1)); |
| EXPECT_FALSE(context.IsInside(2)); |
| EXPECT_FALSE(context.IsInside(3)); |
| { |
| SyntaxTreeNode node2(2); |
| SyntaxTreeContext::AutoPop p2(&context, &node2); |
| EXPECT_TRUE(context.IsInside(1)); |
| EXPECT_TRUE(context.IsInside(2)); |
| EXPECT_FALSE(context.IsInside(3)); |
| { |
| SyntaxTreeNode node3(3); |
| SyntaxTreeContext::AutoPop p3(&context, &node3); |
| EXPECT_TRUE(context.IsInside(1)); |
| EXPECT_TRUE(context.IsInside(2)); |
| EXPECT_TRUE(context.IsInside(3)); |
| // With an offset, we won't see some of these elements |
| EXPECT_TRUE(context.IsInsideStartingFrom(3, 0)); |
| EXPECT_FALSE(context.IsInsideStartingFrom(3, 1)); |
| EXPECT_TRUE(context.IsInsideStartingFrom(2, 1)); |
| EXPECT_FALSE(context.IsInsideStartingFrom(2, 2)); |
| // Check stack boundary |
| EXPECT_FALSE(context.IsInsideStartingFrom(2, 3)); |
| EXPECT_FALSE(context.IsInsideStartingFrom(2, 4)); |
| } |
| } |
| } |
| } |
| |
| // Test that IsInsideFirst correctly reports whether context matches. |
| TEST(SyntaxTreeContextTest, IsInsideFirstTest) { |
| SyntaxTreeContext context; |
| EXPECT_FALSE(context.IsInsideFirst({1, 2, 3}, {0})); |
| { |
| SyntaxTreeNode node1(1); |
| SyntaxTreeContext::AutoPop p1(&context, &node1); |
| EXPECT_TRUE(context.IsInsideFirst({1}, {0, 2, 3})); |
| EXPECT_FALSE(context.IsInsideFirst({0}, {1, 2, 3})); |
| { |
| SyntaxTreeNode node2(2); |
| SyntaxTreeContext::AutoPop p2(&context, &node2); |
| EXPECT_TRUE(context.IsInsideFirst({2}, {0, 1, 3})); |
| EXPECT_TRUE(context.IsInsideFirst({1}, {0})); |
| EXPECT_FALSE(context.IsInsideFirst({1}, {2})); |
| EXPECT_TRUE(context.IsInsideFirst({1, 2}, {0})); |
| EXPECT_TRUE(context.IsInsideFirst({1, 3}, {0})); |
| { |
| SyntaxTreeNode node3(3); |
| SyntaxTreeContext::AutoPop p3(&context, &node3); |
| EXPECT_TRUE(context.IsInsideFirst({2}, {0, 1})); |
| EXPECT_TRUE(context.IsInsideFirst({3}, {0, 1, 2})); |
| EXPECT_TRUE(context.IsInsideFirst({1}, {0})); |
| EXPECT_FALSE(context.IsInsideFirst({1}, {2})); |
| EXPECT_FALSE(context.IsInsideFirst({1}, {3})); |
| EXPECT_TRUE(context.IsInsideFirst({2}, {0})); |
| EXPECT_TRUE(context.IsInsideFirst({2}, {1})); |
| EXPECT_FALSE(context.IsInsideFirst({2}, {3})); |
| EXPECT_TRUE(context.IsInsideFirst({3}, {0})); |
| EXPECT_TRUE(context.IsInsideFirst({3}, {1})); |
| EXPECT_TRUE(context.IsInsideFirst({3}, {2})); |
| EXPECT_TRUE(context.IsInsideFirst({1, 3}, {2})); |
| EXPECT_FALSE(context.IsInsideFirst({1, 2}, {3})); |
| } |
| } |
| } |
| } |
| |
| TEST(SyntaxTreeContextTest, DirectParentIsTest) { |
| SyntaxTreeContext context; |
| // initially empty, always false |
| EXPECT_FALSE(context.DirectParentIs(0)); |
| EXPECT_FALSE(context.DirectParentIs(1)); |
| EXPECT_FALSE(context.DirectParentIs(2)); |
| { |
| SyntaxTreeNode node1(1); |
| SyntaxTreeContext::AutoPop p1(&context, &node1); |
| EXPECT_FALSE(context.DirectParentIs(0)); |
| EXPECT_TRUE(context.DirectParentIs(1)); |
| EXPECT_FALSE(context.DirectParentIs(2)); |
| { |
| SyntaxTreeNode node2(2); |
| SyntaxTreeContext::AutoPop p2(&context, &node2); |
| EXPECT_FALSE(context.DirectParentIs(0)); |
| EXPECT_FALSE(context.DirectParentIs(1)); |
| EXPECT_TRUE(context.DirectParentIs(2)); |
| { |
| SyntaxTreeNode node3(5); |
| SyntaxTreeContext::AutoPop p3(&context, &node3); |
| EXPECT_FALSE(context.DirectParentIs(0)); |
| EXPECT_FALSE(context.DirectParentIs(1)); |
| EXPECT_FALSE(context.DirectParentIs(2)); |
| } |
| } |
| } |
| } |
| |
| TEST(SyntaxTreeContextTest, DirectParentIsOneOfTest) { |
| SyntaxTreeContext context; |
| // initially empty, always false |
| EXPECT_FALSE(context.DirectParentIsOneOf({0, 3, 6})); |
| EXPECT_FALSE(context.DirectParentIsOneOf({1, 4, 7})); |
| EXPECT_FALSE(context.DirectParentIsOneOf({2, 5, 9})); |
| { |
| SyntaxTreeNode node1(1); |
| SyntaxTreeContext::AutoPop p1(&context, &node1); |
| EXPECT_FALSE(context.DirectParentIsOneOf({0, 3, 6})); |
| EXPECT_TRUE(context.DirectParentIsOneOf({1, 4, 7})); |
| EXPECT_FALSE(context.DirectParentIsOneOf({2, 5, 8})); |
| { |
| SyntaxTreeNode node2(5); |
| SyntaxTreeContext::AutoPop p2(&context, &node2); |
| EXPECT_FALSE(context.DirectParentIsOneOf({0, 3, 6})); |
| EXPECT_FALSE(context.DirectParentIsOneOf({1, 4, 7})); |
| EXPECT_TRUE(context.DirectParentIsOneOf({2, 5, 8})); |
| { |
| SyntaxTreeNode node3(9); |
| SyntaxTreeContext::AutoPop p3(&context, &node3); |
| EXPECT_FALSE(context.DirectParentIsOneOf({0, 3, 6})); |
| EXPECT_FALSE(context.DirectParentIsOneOf({1, 4, 7})); |
| EXPECT_FALSE(context.DirectParentIsOneOf({2, 5, 8})); |
| } |
| } |
| } |
| } |
| |
| TEST(SyntaxTreeContextTest, DirectParentsAreTest) { |
| SyntaxTreeContext context; |
| // initially empty, always false |
| EXPECT_TRUE(context.DirectParentsAre<int>({})); // degenerate case |
| EXPECT_FALSE(context.DirectParentsAre({0})); |
| EXPECT_FALSE(context.DirectParentsAre({1})); |
| EXPECT_FALSE(context.DirectParentsAre({0, 1})); |
| { |
| SyntaxTreeNode node1(1); |
| SyntaxTreeContext::AutoPop p1(&context, &node1); |
| EXPECT_TRUE(context.DirectParentsAre<int>({})); // degenerate case |
| EXPECT_FALSE(context.DirectParentsAre({0})); |
| EXPECT_TRUE(context.DirectParentsAre({1})); |
| EXPECT_FALSE(context.DirectParentsAre({1, 0})); |
| EXPECT_FALSE(context.DirectParentsAre({0, 1})); |
| EXPECT_FALSE(context.DirectParentsAre({1, 1})); |
| { |
| SyntaxTreeNode node2(2); |
| SyntaxTreeContext::AutoPop p2(&context, &node2); |
| EXPECT_FALSE(context.DirectParentsAre({1})); |
| EXPECT_TRUE(context.DirectParentsAre({2})); |
| EXPECT_FALSE(context.DirectParentsAre({1, 2})); |
| EXPECT_TRUE(context.DirectParentsAre({2, 1})); |
| EXPECT_FALSE(context.DirectParentsAre({1, 1})); |
| EXPECT_FALSE(context.DirectParentsAre({2, 2})); |
| EXPECT_FALSE(context.DirectParentsAre({2, 1, 0})); |
| { |
| SyntaxTreeNode node3(5); |
| SyntaxTreeContext::AutoPop p3(&context, &node3); |
| EXPECT_FALSE(context.DirectParentsAre({1})); |
| EXPECT_FALSE(context.DirectParentsAre({2})); |
| EXPECT_TRUE(context.DirectParentsAre({5})); |
| EXPECT_TRUE(context.DirectParentsAre({5, 2})); |
| EXPECT_TRUE(context.DirectParentsAre({5, 2, 1})); |
| EXPECT_FALSE(context.DirectParentsAre({3, 2, 1})); |
| EXPECT_FALSE(context.DirectParentsAre({1, 2, 5})); |
| EXPECT_FALSE(context.DirectParentsAre({5, 5})); |
| EXPECT_FALSE(context.DirectParentsAre({5, 1})); |
| EXPECT_FALSE(context.DirectParentsAre({5, 2, 1, 0})); |
| } |
| } |
| } |
| } |
| |
| TEST(SyntaxTreeContextTest, NearestParentMatchingTest) { |
| // define a few predicate functions |
| const auto True = [](const SyntaxTreeNode& n) { return true; }; |
| const auto TagEq = [](int i) { |
| return [i](const SyntaxTreeNode& n) { return n.Tag().tag == i; }; |
| }; |
| |
| SyntaxTreeContext context; |
| // initially empty, always nullptr regardless of predicate |
| EXPECT_EQ(context.NearestParentMatching(True), nullptr); |
| { |
| SyntaxTreeNode node1(1); |
| SyntaxTreeContext::AutoPop p1(&context, &node1); |
| EXPECT_EQ(context.NearestParentMatching(True), &node1); |
| EXPECT_EQ(context.NearestParentMatching(TagEq(0)), nullptr); |
| EXPECT_EQ(context.NearestParentWithTag(0), nullptr); |
| EXPECT_EQ(context.NearestParentMatching(TagEq(1)), &node1); |
| EXPECT_EQ(context.NearestParentWithTag(1), &node1); |
| { |
| SyntaxTreeNode node2(1); |
| SyntaxTreeContext::AutoPop p2(&context, &node2); |
| EXPECT_EQ(context.NearestParentMatching(True), &node2); |
| EXPECT_EQ(context.NearestParentMatching(TagEq(0)), nullptr); |
| EXPECT_EQ(context.NearestParentWithTag(0), nullptr); |
| EXPECT_EQ(context.NearestParentMatching(TagEq(1)), &node2); |
| EXPECT_EQ(context.NearestParentWithTag(1), &node2); |
| { |
| SyntaxTreeNode node3(3); |
| SyntaxTreeContext::AutoPop p3(&context, &node3); |
| EXPECT_EQ(context.NearestParentMatching(True), &node3); |
| EXPECT_EQ(context.NearestParentMatching(TagEq(0)), nullptr); |
| EXPECT_EQ(context.NearestParentWithTag(0), nullptr); |
| EXPECT_EQ(context.NearestParentMatching(TagEq(1)), &node2); |
| EXPECT_EQ(context.NearestParentWithTag(1), &node2); |
| EXPECT_EQ(context.NearestParentMatching(TagEq(3)), &node3); |
| EXPECT_EQ(context.NearestParentWithTag(3), &node3); |
| } |
| } |
| } |
| } |
| |
| } // namespace |
| } // namespace verible |