1 //===--- LRTableTest.cpp - ---------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang-pseudo/grammar/LRTable.h"
10 #include "clang-pseudo/grammar/Grammar.h"
11 #include "clang/Basic/TokenKinds.h"
12 #include "llvm/Testing/Support/SupportHelpers.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15 #include <vector>
16 
17 namespace clang {
18 namespace pseudo {
19 namespace {
20 
21 using llvm::ValueIs;
22 using testing::ElementsAre;
23 using Action = LRTable::Action;
24 
25 TEST(LRTable, Builder) {
26   std::vector<std::string> GrammarDiags;
27   Grammar G = Grammar::parseBNF(R"bnf(
28     _ := expr            # rule 0
29     expr := term         # rule 1
30     expr := expr + term  # rule 2
31     term := IDENTIFIER   # rule 3
32   )bnf",
33                                 GrammarDiags);
34   EXPECT_THAT(GrammarDiags, testing::IsEmpty());
35 
36   SymbolID Term = *G.findNonterminal("term");
37   SymbolID Eof = tokenSymbol(tok::eof);
38   SymbolID Identifier = tokenSymbol(tok::identifier);
39   SymbolID Plus = tokenSymbol(tok::plus);
40 
41   //           eof  IDENT   term
42   // +-------+----+-------+------+
43   // |state0 |    | s0    |      |
44   // |state1 |    |       | g3   |
45   // |state2 |    |       |      |
46   // +-------+----+-------+------+-------
47   std::vector<LRTable::Entry> Entries = {
48       {/* State */ 0, Identifier, Action::shift(0)},
49       {/* State */ 1, Term, Action::goTo(3)},
50   };
51   std::vector<LRTable::ReduceEntry> ReduceEntries = {
52       {/*State=*/0, /*Rule=*/0},
53       {/*State=*/1, /*Rule=*/2},
54       {/*State=*/2, /*Rule=*/1},
55   };
56   LRTable T = LRTable::buildForTests(G, Entries, ReduceEntries);
57   EXPECT_EQ(T.getShiftState(0, Eof), llvm::None);
58   EXPECT_THAT(T.getShiftState(0, Identifier), ValueIs(0));
59   EXPECT_THAT(T.getReduceRules(0), ElementsAre(0));
60 
61   EXPECT_EQ(T.getShiftState(1, Eof), llvm::None);
62   EXPECT_EQ(T.getShiftState(1, Identifier), llvm::None);
63   EXPECT_EQ(T.getGoToState(1, Term), 3);
64   EXPECT_THAT(T.getReduceRules(1), ElementsAre(2));
65 
66   // Verify the behaivor for other non-available-actions terminals.
67   SymbolID Int = tokenSymbol(tok::kw_int);
68   EXPECT_EQ(T.getShiftState(2, Int), llvm::None);
69 
70   // Check follow sets.
71   EXPECT_TRUE(T.canFollow(Term, Plus));
72   EXPECT_TRUE(T.canFollow(Term, Eof));
73   EXPECT_FALSE(T.canFollow(Term, Int));
74 }
75 
76 } // namespace
77 } // namespace pseudo
78 } // namespace clang
79