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 StateID = LRTable::StateID; |
24 | |
25 | TEST(LRTable, Builder) { |
26 | std::vector<std::string> GrammarDiags; |
27 | Grammar G = Grammar::parseBNF(BNF: 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 | Diags&: GrammarDiags); |
34 | EXPECT_THAT(GrammarDiags, testing::IsEmpty()); |
35 | |
36 | SymbolID Term = *G.findNonterminal(Name: "term" ); |
37 | SymbolID Eof = tokenSymbol(TK: tok::eof); |
38 | SymbolID Identifier = tokenSymbol(TK: tok::identifier); |
39 | SymbolID Plus = tokenSymbol(TK: tok::plus); |
40 | |
41 | LRTable::Builder B(G); |
42 | // eof IDENT term |
43 | // +-------+----+-------+------+ |
44 | // |state0 | | s0 | | |
45 | // |state1 | | | g3 | |
46 | // |state2 | | | | |
47 | // +-------+----+-------+------+------- |
48 | B.Transition[{StateID{0}, Identifier}] = StateID{0}; |
49 | B.Transition[{StateID{1}, Term}] = StateID{3}; |
50 | B.Reduce[StateID{0}].insert(V: RuleID{0}); |
51 | B.Reduce[StateID{1}].insert(V: RuleID{2}); |
52 | B.Reduce[StateID{2}].insert(V: RuleID{1}); |
53 | LRTable T = std::move(B).build(); |
54 | |
55 | EXPECT_EQ(T.getShiftState(0, Eof), std::nullopt); |
56 | EXPECT_THAT(T.getShiftState(0, Identifier), ValueIs(0)); |
57 | EXPECT_THAT(T.getReduceRules(0), ElementsAre(0)); |
58 | |
59 | EXPECT_EQ(T.getShiftState(1, Eof), std::nullopt); |
60 | EXPECT_EQ(T.getShiftState(1, Identifier), std::nullopt); |
61 | EXPECT_THAT(T.getGoToState(1, Term), ValueIs(3)); |
62 | EXPECT_THAT(T.getReduceRules(1), ElementsAre(2)); |
63 | |
64 | // Verify the behaivor for other non-available-actions terminals. |
65 | SymbolID Int = tokenSymbol(TK: tok::kw_int); |
66 | EXPECT_EQ(T.getShiftState(2, Int), std::nullopt); |
67 | |
68 | // Check follow sets. |
69 | EXPECT_TRUE(T.canFollow(Term, Plus)); |
70 | EXPECT_TRUE(T.canFollow(Term, Eof)); |
71 | EXPECT_FALSE(T.canFollow(Term, Int)); |
72 | } |
73 | |
74 | } // namespace |
75 | } // namespace pseudo |
76 | } // namespace clang |
77 | |