[pseudo] Grammar::parseBNF returns Grammar not unique_ptr. NFC

This commit is contained in:
Sam McCall 2022-06-28 16:24:38 +02:00
parent 313f9cd81d
commit 3f028c02ba
11 changed files with 109 additions and 113 deletions

View File

@ -67,7 +67,7 @@ void setupGrammarAndSource() {
GrammarText = new std::string(ReadFile(GrammarFile));
SourceText = new std::string(ReadFile(Source));
std::vector<std::string> Diags;
G = Grammar::parseBNF(*GrammarText, Diags).release();
G = new Grammar(Grammar::parseBNF(*GrammarText, Diags));
}
static void parseBNF(benchmark::State &State) {

View File

@ -24,7 +24,7 @@ namespace {
class Fuzzer {
clang::LangOptions LangOpts = clang::pseudo::genericLangOpts();
std::unique_ptr<Grammar> G;
Grammar G;
LRTable T;
bool Print;
@ -44,7 +44,7 @@ public:
llvm::errs() << Diag << "\n";
std::exit(1);
}
T = LRTable::buildSLR(*G);
T = LRTable::buildSLR(G);
}
void operator()(llvm::StringRef Code) {
@ -59,10 +59,10 @@ public:
clang::pseudo::ForestArena Arena;
clang::pseudo::GSS GSS;
auto &Root =
glrParse(ParseableStream, clang::pseudo::ParseParams{*G, T, Arena, GSS},
*G->findNonterminal("translation-unit"));
glrParse(ParseableStream, clang::pseudo::ParseParams{G, T, Arena, GSS},
*G.findNonterminal("translation-unit"));
if (Print)
llvm::outs() << Root.dumpRecursive(*G);
llvm::outs() << Root.dumpRecursive(G);
}
};

View File

@ -79,9 +79,9 @@ int main(int argc, char *argv[]) {
switch (Emit) {
case EmitSymbolList:
for (clang::pseudo::SymbolID ID = 0; ID < G->table().Nonterminals.size();
for (clang::pseudo::SymbolID ID = 0; ID < G.table().Nonterminals.size();
++ID) {
std::string Name = G->symbolName(ID).str();
std::string Name = G.symbolName(ID).str();
// translation-unit -> translation_unit
std::replace(Name.begin(), Name.end(), '-', '_');
Out.os() << llvm::formatv("NONTERMINAL({0}, {1})\n", Name, ID);

View File

@ -138,12 +138,12 @@ struct GrammarTable;
// It is a building block for constructing a table-based parser.
class Grammar {
public:
Grammar() = default; // Creates an invalid dummy grammar.
explicit Grammar(std::unique_ptr<GrammarTable>);
// Parses grammar from a BNF file.
// Diagnostics emitted during parsing are stored in Diags.
static std::unique_ptr<Grammar> parseBNF(llvm::StringRef BNF,
std::vector<std::string> &Diags);
static Grammar parseBNF(llvm::StringRef BNF, std::vector<std::string> &Diags);
// Returns the SymbolID of the symbol '_'.
SymbolID underscore() const { return Underscore; };

View File

@ -19,7 +19,7 @@ static const char *CXXBNF =
const Grammar &getGrammar() {
static std::vector<std::string> Diags;
static Grammar *G = Grammar::parseBNF(CXXBNF, Diags).release();
static Grammar *G = new Grammar(Grammar::parseBNF(CXXBNF, Diags));
assert(Diags.empty());
return *G;
}

View File

@ -28,7 +28,7 @@ public:
GrammarBuilder(std::vector<std::string> &Diagnostics)
: Diagnostics(Diagnostics) {}
std::unique_ptr<Grammar> build(llvm::StringRef BNF) {
Grammar build(llvm::StringRef BNF) {
auto Specs = eliminateOptional(parse(BNF));
assert(llvm::all_of(Specs,
@ -122,8 +122,8 @@ public:
++End;
T->Nonterminals[SID].RuleRange = {Start, End};
}
auto G = std::make_unique<Grammar>(std::move(T));
diagnoseGrammar(*G);
Grammar G(std::move(T));
diagnoseGrammar(G);
return G;
}
@ -341,8 +341,8 @@ private:
};
} // namespace
std::unique_ptr<Grammar>
Grammar::parseBNF(llvm::StringRef BNF, std::vector<std::string> &Diagnostics) {
Grammar Grammar::parseBNF(llvm::StringRef BNF,
std::vector<std::string> &Diagnostics) {
Diagnostics.clear();
return GrammarBuilder(Diagnostics).build(BNF);
}

View File

@ -105,12 +105,12 @@ int main(int argc, char *argv[]) {
llvm::outs() << llvm::formatv("grammar file {0} is parsed successfully\n",
Grammar);
if (PrintGrammar)
llvm::outs() << G->dump();
llvm::outs() << G.dump();
if (PrintGraph)
llvm::outs() << clang::pseudo::LRGraph::buildLR0(*G).dumpForTests(*G);
auto LRTable = clang::pseudo::LRTable::buildSLR(*G);
llvm::outs() << clang::pseudo::LRGraph::buildLR0(G).dumpForTests(G);
auto LRTable = clang::pseudo::LRTable::buildSLR(G);
if (PrintTable)
llvm::outs() << LRTable.dumpForTests(*G);
llvm::outs() << LRTable.dumpForTests(G);
if (PrintStatistics)
llvm::outs() << LRTable.dumpStatistics();
@ -118,17 +118,17 @@ int main(int argc, char *argv[]) {
clang::pseudo::ForestArena Arena;
clang::pseudo::GSS GSS;
llvm::Optional<clang::pseudo::SymbolID> StartSymID =
G->findNonterminal(StartSymbol);
G.findNonterminal(StartSymbol);
if (!StartSymID) {
llvm::errs() << llvm::formatv(
"The start symbol {0} doesn't exit in the grammar!\n", Grammar);
return 2;
}
auto &Root = glrParse(*ParseableStream,
clang::pseudo::ParseParams{*G, LRTable, Arena, GSS},
clang::pseudo::ParseParams{G, LRTable, Arena, GSS},
*StartSymID);
if (PrintForest)
llvm::outs() << Root.dumpRecursive(*G, /*Abbreviated=*/true);
llvm::outs() << Root.dumpRecursive(G, /*Abbreviated=*/true);
if (PrintStatistics) {
llvm::outs() << "Forest bytes: " << Arena.bytes()

View File

@ -28,19 +28,19 @@ public:
SymbolID symbol(llvm::StringRef Name) const {
for (unsigned I = 0; I < NumTerminals; ++I)
if (G->table().Terminals[I] == Name)
if (G.table().Terminals[I] == Name)
return tokenSymbol(static_cast<tok::TokenKind>(I));
for (SymbolID ID = 0; ID < G->table().Nonterminals.size(); ++ID)
if (G->table().Nonterminals[ID].Name == Name)
for (SymbolID ID = 0; ID < G.table().Nonterminals.size(); ++ID)
if (G.table().Nonterminals[ID].Name == Name)
return ID;
ADD_FAILURE() << "No such symbol found: " << Name;
return 0;
}
RuleID ruleFor(llvm::StringRef NonterminalName) const {
auto RuleRange = G->table().Nonterminals[symbol(NonterminalName)].RuleRange;
auto RuleRange = G.table().Nonterminals[symbol(NonterminalName)].RuleRange;
if (RuleRange.End - RuleRange.Start == 1)
return G->table().Nonterminals[symbol(NonterminalName)].RuleRange.Start;
return G.table().Nonterminals[symbol(NonterminalName)].RuleRange.Start;
ADD_FAILURE() << "Expected a single rule for " << NonterminalName
<< ", but it has " << RuleRange.End - RuleRange.Start
<< " rule!\n";
@ -48,7 +48,7 @@ public:
}
protected:
std::unique_ptr<Grammar> G;
Grammar G;
std::vector<std::string> Diags;
};
@ -73,12 +73,12 @@ TEST_F(ForestTest, DumpBasic) {
const auto *Add =
&Arena.createSequence(symbol("add-expression"), ruleFor("add-expression"),
{Left, &T[1], Right});
EXPECT_EQ(Add->dumpRecursive(*G, true),
EXPECT_EQ(Add->dumpRecursive(G, true),
"[ 0, end) add-expression := id-expression + id-expression\n"
"[ 0, 1) ├─id-expression~IDENTIFIER := tok[0]\n"
"[ 1, 2) ├─+ := tok[1]\n"
"[ 2, end) └─id-expression~IDENTIFIER := tok[2]\n");
EXPECT_EQ(Add->dumpRecursive(*G, false),
EXPECT_EQ(Add->dumpRecursive(G, false),
"[ 0, end) add-expression := id-expression + id-expression\n"
"[ 0, 1) ├─id-expression := IDENTIFIER\n"
"[ 0, 1) │ └─IDENTIFIER := tok[0]\n"
@ -114,7 +114,7 @@ TEST_F(ForestTest, DumpAmbiguousAndRefs) {
&Arena.createSequence(symbol("type"), /*RuleID=*/4, {EnumType});
const auto *Type =
&Arena.createAmbiguous(symbol("type"), {Alternative1, Alternative2});
EXPECT_EQ(Type->dumpRecursive(*G),
EXPECT_EQ(Type->dumpRecursive(G),
"[ 0, end) type := <ambiguous>\n"
"[ 0, end) ├─type := class-type\n"
"[ 0, end) │ └─class-type := shared-type\n"

View File

@ -66,19 +66,19 @@ public:
SymbolID id(llvm::StringRef Name) const {
for (unsigned I = 0; I < NumTerminals; ++I)
if (G->table().Terminals[I] == Name)
if (G.table().Terminals[I] == Name)
return tokenSymbol(static_cast<tok::TokenKind>(I));
for (SymbolID ID = 0; ID < G->table().Nonterminals.size(); ++ID)
if (G->table().Nonterminals[ID].Name == Name)
for (SymbolID ID = 0; ID < G.table().Nonterminals.size(); ++ID)
if (G.table().Nonterminals[ID].Name == Name)
return ID;
ADD_FAILURE() << "No such symbol found: " << Name;
return 0;
}
RuleID ruleFor(llvm::StringRef NonterminalName) const {
auto RuleRange = G->table().Nonterminals[id(NonterminalName)].RuleRange;
auto RuleRange = G.table().Nonterminals[id(NonterminalName)].RuleRange;
if (RuleRange.End - RuleRange.Start == 1)
return G->table().Nonterminals[id(NonterminalName)].RuleRange.Start;
return G.table().Nonterminals[id(NonterminalName)].RuleRange.Start;
ADD_FAILURE() << "Expected a single rule for " << NonterminalName
<< ", but it has " << RuleRange.End - RuleRange.Start
<< " rule!\n";
@ -86,7 +86,7 @@ public:
}
protected:
std::unique_ptr<Grammar> G;
Grammar G;
ForestArena Arena;
GSS GSStack;
};
@ -113,7 +113,7 @@ TEST_F(GLRTest, ShiftMergingHeads) {
buildGrammar({}, {}); // Create a fake empty grammar.
LRTable T =
LRTable::buildForTests(*G, /*Entries=*/
LRTable::buildForTests(G, /*Entries=*/
{
{1, tokenSymbol(tok::semi), Action::shift(4)},
{2, tokenSymbol(tok::semi), Action::shift(4)},
@ -123,8 +123,8 @@ TEST_F(GLRTest, ShiftMergingHeads) {
ForestNode &SemiTerminal = Arena.createTerminal(tok::semi, 0);
std::vector<const GSS::Node *> NewHeads;
glrShift({GSSNode1, GSSNode2, GSSNode3}, SemiTerminal,
{*G, T, Arena, GSStack}, NewHeads);
glrShift({GSSNode1, GSSNode2, GSSNode3}, SemiTerminal, {G, T, Arena, GSStack},
NewHeads);
EXPECT_THAT(NewHeads,
UnorderedElementsAre(AllOf(state(4), parsedSymbol(&SemiTerminal),
@ -145,7 +145,7 @@ TEST_F(GLRTest, ReduceConflictsSplitting) {
{"class-name := IDENTIFIER", "enum-name := IDENTIFIER"});
LRTable Table = LRTable::buildForTests(
*G,
G,
{
{/*State=*/0, id("class-name"), Action::goTo(2)},
{/*State=*/0, id("enum-name"), Action::goTo(3)},
@ -161,7 +161,7 @@ TEST_F(GLRTest, ReduceConflictsSplitting) {
GSStack.addNode(1, &Arena.createTerminal(tok::identifier, 0), {GSSNode0});
std::vector<const GSS::Node *> Heads = {GSSNode1};
glrReduce(Heads, tokenSymbol(tok::eof), {*G, Table, Arena, GSStack});
glrReduce(Heads, tokenSymbol(tok::eof), {G, Table, Arena, GSStack});
EXPECT_THAT(Heads, UnorderedElementsAre(
GSSNode1,
AllOf(state(2), parsedSymbolID(id("class-name")),
@ -193,7 +193,7 @@ TEST_F(GLRTest, ReduceSplittingDueToMultipleBases) {
/*Parents=*/{GSSNode2, GSSNode3});
LRTable Table = LRTable::buildForTests(
*G,
G,
{
{/*State=*/2, id("ptr-operator"), Action::goTo(/*NextState=*/5)},
{/*State=*/3, id("ptr-operator"), Action::goTo(/*NextState=*/6)},
@ -202,7 +202,7 @@ TEST_F(GLRTest, ReduceSplittingDueToMultipleBases) {
{/*State=*/4, ruleFor("ptr-operator")},
});
std::vector<const GSS::Node *> Heads = {GSSNode4};
glrReduce(Heads, tokenSymbol(tok::eof), {*G, Table, Arena, GSStack});
glrReduce(Heads, tokenSymbol(tok::eof), {G, Table, Arena, GSStack});
EXPECT_THAT(Heads, UnorderedElementsAre(
GSSNode4,
@ -247,7 +247,7 @@ TEST_F(GLRTest, ReduceJoiningWithMultipleBases) {
// FIXME: figure out a way to get rid of the hard-coded reduce RuleID!
LRTable Table = LRTable::buildForTests(
*G,
G,
{
{/*State=*/1, id("type-name"), Action::goTo(/*NextState=*/5)},
{/*State=*/2, id("type-name"), Action::goTo(/*NextState=*/5)},
@ -257,7 +257,7 @@ TEST_F(GLRTest, ReduceJoiningWithMultipleBases) {
{/*State=*/4, /* type-name := enum-name */ 1},
});
std::vector<const GSS::Node *> Heads = {GSSNode3, GSSNode4};
glrReduce(Heads, tokenSymbol(tok::eof), {*G, Table, Arena, GSStack});
glrReduce(Heads, tokenSymbol(tok::eof), {G, Table, Arena, GSStack});
// Verify that the stack heads are joint at state 5 after reduces.
EXPECT_THAT(Heads, UnorderedElementsAre(GSSNode3, GSSNode4,
@ -266,7 +266,7 @@ TEST_F(GLRTest, ReduceJoiningWithMultipleBases) {
parents({GSSNode1, GSSNode2}))))
<< Heads;
// Verify that we create an ambiguous ForestNode of two parses of `type-name`.
EXPECT_EQ(Heads.back()->Payload->dumpRecursive(*G),
EXPECT_EQ(Heads.back()->Payload->dumpRecursive(G),
"[ 1, end) type-name := <ambiguous>\n"
"[ 1, end) ├─type-name := class-name\n"
"[ 1, end) │ └─class-name := <opaque>\n"
@ -305,7 +305,7 @@ TEST_F(GLRTest, ReduceJoiningWithSameBase) {
// FIXME: figure out a way to get rid of the hard-coded reduce RuleID!
LRTable Table =
LRTable::buildForTests(*G,
LRTable::buildForTests(G,
{
{/*State=*/0, id("pointer"), Action::goTo(5)},
},
@ -314,14 +314,14 @@ TEST_F(GLRTest, ReduceJoiningWithSameBase) {
{4, /* pointer := enum-name */ 1},
});
std::vector<const GSS::Node *> Heads = {GSSNode3, GSSNode4};
glrReduce(Heads, tokenSymbol(tok::eof), {*G, Table, Arena, GSStack});
glrReduce(Heads, tokenSymbol(tok::eof), {G, Table, Arena, GSStack});
EXPECT_THAT(
Heads, UnorderedElementsAre(GSSNode3, GSSNode4,
AllOf(state(5), parsedSymbolID(id("pointer")),
parents({GSSNode0}))))
<< Heads;
EXPECT_EQ(Heads.back()->Payload->dumpRecursive(*G),
EXPECT_EQ(Heads.back()->Payload->dumpRecursive(G),
"[ 0, end) pointer := <ambiguous>\n"
"[ 0, end) ├─pointer := class-name *\n"
"[ 0, 1) │ ├─class-name := <opaque>\n"
@ -335,7 +335,7 @@ TEST_F(GLRTest, ReduceLookahead) {
// A term can be followed by +, but not by -.
buildGrammar({"sum", "term"}, {"expr := term + term", "term := IDENTIFIER"});
LRTable Table =
LRTable::buildForTests(*G,
LRTable::buildForTests(G,
{
{/*State=*/0, id("term"), Action::goTo(2)},
},
@ -352,14 +352,14 @@ TEST_F(GLRTest, ReduceLookahead) {
// When the lookahead is +, reduce is performed.
std::vector<const GSS::Node *> Heads = {GSSNode1};
glrReduce(Heads, tokenSymbol(tok::plus), {*G, Table, Arena, GSStack});
glrReduce(Heads, tokenSymbol(tok::plus), {G, Table, Arena, GSStack});
EXPECT_THAT(Heads,
ElementsAre(GSSNode1, AllOf(state(2), parsedSymbolID(id("term")),
parents(Root))));
// When the lookahead is -, reduce is not performed.
Heads = {GSSNode1};
glrReduce(Heads, tokenSymbol(tok::minus), {*G, Table, Arena, GSStack});
glrReduce(Heads, tokenSymbol(tok::minus), {G, Table, Arena, GSStack});
EXPECT_THAT(Heads, ElementsAre(GSSNode1));
}
@ -382,26 +382,25 @@ TEST_F(GLRTest, PerfectForestNodeSharing) {
)bnf");
clang::LangOptions LOptions;
const TokenStream &Tokens = cook(lex("{ abc", LOptions), LOptions);
auto LRTable = LRTable::buildSLR(*G);
auto LRTable = LRTable::buildSLR(G);
const ForestNode &Parsed =
glrParse(Tokens, {*G, LRTable, Arena, GSStack}, id("test"));
glrParse(Tokens, {G, LRTable, Arena, GSStack}, id("test"));
// Verify that there is no duplicated sequence node of `expr := IDENTIFIER`
// in the forest, see the `#1` and `=#1` in the dump string.
EXPECT_EQ(Parsed.dumpRecursive(*G),
"[ 0, end) test := <ambiguous>\n"
"[ 0, end) ├─test := { expr\n"
"[ 0, 1) │ ├─{ := tok[0]\n"
"[ 1, end) │ └─expr := IDENTIFIER #1\n"
"[ 1, end) │ └─IDENTIFIER := tok[1]\n"
"[ 0, end) ├─test := { IDENTIFIER\n"
"[ 0, 1) │ ├─{ := tok[0]\n"
"[ 1, end) │ └─IDENTIFIER := tok[1]\n"
"[ 0, end) └─test := left-paren expr\n"
"[ 0, 1) ├─left-paren := {\n"
"[ 0, 1) │ └─{ := tok[0]\n"
"[ 1, end) └─expr := IDENTIFIER =#1\n"
"[ 1, end) └─IDENTIFIER := tok[1]\n");
EXPECT_EQ(Parsed.dumpRecursive(G), "[ 0, end) test := <ambiguous>\n"
"[ 0, end) ├─test := { expr\n"
"[ 0, 1) │ ├─{ := tok[0]\n"
"[ 1, end) │ └─expr := IDENTIFIER #1\n"
"[ 1, end) │ └─IDENTIFIER := tok[1]\n"
"[ 0, end) ├─test := { IDENTIFIER\n"
"[ 0, 1) │ ├─{ := tok[0]\n"
"[ 1, end) │ └─IDENTIFIER := tok[1]\n"
"[ 0, end) └─test := left-paren expr\n"
"[ 0, 1) ├─left-paren := {\n"
"[ 0, 1) │ └─{ := tok[0]\n"
"[ 1, end) └─expr := IDENTIFIER =#1\n"
"[ 1, end) └─IDENTIFIER := tok[1]\n");
}
TEST_F(GLRTest, GLRReduceOrder) {
@ -420,17 +419,16 @@ TEST_F(GLRTest, GLRReduceOrder) {
)bnf");
clang::LangOptions LOptions;
const TokenStream &Tokens = cook(lex("IDENTIFIER", LOptions), LOptions);
auto LRTable = LRTable::buildSLR(*G);
auto LRTable = LRTable::buildSLR(G);
const ForestNode &Parsed =
glrParse(Tokens, {*G, LRTable, Arena, GSStack}, id("test"));
EXPECT_EQ(Parsed.dumpRecursive(*G),
"[ 0, end) test := <ambiguous>\n"
"[ 0, end) ├─test := IDENTIFIER\n"
"[ 0, end) │ └─IDENTIFIER := tok[0]\n"
"[ 0, end) └─test := foo\n"
"[ 0, end) └─foo := IDENTIFIER\n"
"[ 0, end) └─IDENTIFIER := tok[0]\n");
glrParse(Tokens, {G, LRTable, Arena, GSStack}, id("test"));
EXPECT_EQ(Parsed.dumpRecursive(G), "[ 0, end) test := <ambiguous>\n"
"[ 0, end) ├─test := IDENTIFIER\n"
"[ 0, end) │ └─IDENTIFIER := tok[0]\n"
"[ 0, end) └─test := foo\n"
"[ 0, end) └─foo := IDENTIFIER\n"
"[ 0, end) └─IDENTIFIER := tok[0]\n");
}
TEST_F(GLRTest, NoExplicitAccept) {
@ -445,15 +443,14 @@ TEST_F(GLRTest, NoExplicitAccept) {
// of the nonterminal `test` when the next token is `eof`, verify that the
// parser stops at the right state.
const TokenStream &Tokens = cook(lex("id id", LOptions), LOptions);
auto LRTable = LRTable::buildSLR(*G);
auto LRTable = LRTable::buildSLR(G);
const ForestNode &Parsed =
glrParse(Tokens, {*G, LRTable, Arena, GSStack}, id("test"));
EXPECT_EQ(Parsed.dumpRecursive(*G),
"[ 0, end) test := IDENTIFIER test\n"
"[ 0, 1) ├─IDENTIFIER := tok[0]\n"
"[ 1, end) └─test := IDENTIFIER\n"
"[ 1, end) └─IDENTIFIER := tok[1]\n");
glrParse(Tokens, {G, LRTable, Arena, GSStack}, id("test"));
EXPECT_EQ(Parsed.dumpRecursive(G), "[ 0, end) test := IDENTIFIER test\n"
"[ 0, 1) ├─IDENTIFIER := tok[0]\n"
"[ 1, end) └─test := IDENTIFIER\n"
"[ 1, end) └─IDENTIFIER := tok[1]\n");
}
TEST(GSSTest, GC) {

View File

@ -35,19 +35,19 @@ public:
SymbolID id(llvm::StringRef Name) const {
for (unsigned I = 0; I < NumTerminals; ++I)
if (G->table().Terminals[I] == Name)
if (G.table().Terminals[I] == Name)
return tokenSymbol(static_cast<tok::TokenKind>(I));
for (SymbolID ID = 0; ID < G->table().Nonterminals.size(); ++ID)
if (G->table().Nonterminals[ID].Name == Name)
for (SymbolID ID = 0; ID < G.table().Nonterminals.size(); ++ID)
if (G.table().Nonterminals[ID].Name == Name)
return ID;
ADD_FAILURE() << "No such symbol found: " << Name;
return 0;
}
RuleID ruleFor(llvm::StringRef NonterminalName) const {
auto RuleRange = G->table().Nonterminals[id(NonterminalName)].RuleRange;
auto RuleRange = G.table().Nonterminals[id(NonterminalName)].RuleRange;
if (RuleRange.End - RuleRange.Start == 1)
return G->table().Nonterminals[id(NonterminalName)].RuleRange.Start;
return G.table().Nonterminals[id(NonterminalName)].RuleRange.Start;
ADD_FAILURE() << "Expected a single rule for " << NonterminalName
<< ", but it has " << RuleRange.End - RuleRange.Start
<< " rule!\n";
@ -55,7 +55,7 @@ public:
}
protected:
std::unique_ptr<Grammar> G;
Grammar G;
std::vector<std::string> Diags;
};
@ -65,19 +65,19 @@ TEST_F(GrammarTest, Basic) {
auto ExpectedRule =
AllOf(TargetID(id("_")), Sequence(id("IDENTIFIER"), id("+"), id("_")));
EXPECT_EQ(G->symbolName(id("_")), "_");
EXPECT_THAT(G->rulesFor(id("_")), UnorderedElementsAre(ExpectedRule));
const auto &Rule = G->lookupRule(/*RID=*/0);
EXPECT_EQ(G.symbolName(id("_")), "_");
EXPECT_THAT(G.rulesFor(id("_")), UnorderedElementsAre(ExpectedRule));
const auto &Rule = G.lookupRule(/*RID=*/0);
EXPECT_THAT(Rule, ExpectedRule);
EXPECT_THAT(G->symbolName(Rule.seq()[0]), "IDENTIFIER");
EXPECT_THAT(G->symbolName(Rule.seq()[1]), "+");
EXPECT_THAT(G->symbolName(Rule.seq()[2]), "_");
EXPECT_THAT(G.symbolName(Rule.seq()[0]), "IDENTIFIER");
EXPECT_THAT(G.symbolName(Rule.seq()[1]), "+");
EXPECT_THAT(G.symbolName(Rule.seq()[2]), "_");
}
TEST_F(GrammarTest, EliminatedOptional) {
build("_ := CONST_opt INT ;_opt");
EXPECT_THAT(Diags, IsEmpty());
EXPECT_THAT(G->table().Rules,
EXPECT_THAT(G.table().Rules,
UnorderedElementsAre(Sequence(id("INT")),
Sequence(id("CONST"), id("INT")),
Sequence(id("CONST"), id("INT"), id(";")),
@ -108,11 +108,10 @@ TEST_F(GrammarTest, Annotation) {
)bnf");
ASSERT_TRUE(Diags.empty());
EXPECT_EQ(G->lookupRule(ruleFor("_")).Guard, 0);
EXPECT_GT(G->lookupRule(ruleFor("x")).Guard, 0);
EXPECT_GT(G->lookupRule(ruleFor("y")).Guard, 0);
EXPECT_NE(G->lookupRule(ruleFor("x")).Guard,
G->lookupRule(ruleFor("y")).Guard);
EXPECT_EQ(G.lookupRule(ruleFor("_")).Guard, 0);
EXPECT_GT(G.lookupRule(ruleFor("x")).Guard, 0);
EXPECT_GT(G.lookupRule(ruleFor("y")).Guard, 0);
EXPECT_NE(G.lookupRule(ruleFor("x")).Guard, G.lookupRule(ruleFor("y")).Guard);
}
TEST_F(GrammarTest, Diagnostics) {
@ -130,7 +129,7 @@ TEST_F(GrammarTest, Diagnostics) {
_ := IDENTIFIER [unknown=value]
)cpp");
EXPECT_EQ(G->underscore(), id("_"));
EXPECT_EQ(G.underscore(), id("_"));
EXPECT_THAT(Diags, UnorderedElementsAre(
"Rule '_ := ,_opt' has a nullable RHS",
"Rule 'null := ' has a nullable RHS",
@ -160,13 +159,13 @@ term := ( expr )
};
EXPECT_THAT(
ToPairs(firstSets(*G)),
ToPairs(firstSets(G)),
UnorderedElementsAre(
Pair(id("_"), UnorderedElementsAre(id("IDENTIFIER"), id("("))),
Pair(id("expr"), UnorderedElementsAre(id("IDENTIFIER"), id("("))),
Pair(id("term"), UnorderedElementsAre(id("IDENTIFIER"), id("(")))));
EXPECT_THAT(
ToPairs(followSets(*G)),
ToPairs(followSets(G)),
UnorderedElementsAre(
Pair(id("_"), UnorderedElementsAre(id("EOF"))),
Pair(id("expr"), UnorderedElementsAre(id("-"), id("EOF"), id(")"))),
@ -183,7 +182,7 @@ simple-type-specifier := INT
)bnf");
ASSERT_TRUE(Diags.empty());
EXPECT_THAT(
ToPairs(firstSets(*G)),
ToPairs(firstSets(G)),
UnorderedElementsAre(
Pair(id("_"), UnorderedElementsAre(id("INLINE"), id("INT"))),
Pair(id("decl-specifier-seq"),
@ -192,7 +191,7 @@ simple-type-specifier := INT
Pair(id("decl-specifier"),
UnorderedElementsAre(id("INLINE"), id("INT")))));
EXPECT_THAT(
ToPairs(followSets(*G)),
ToPairs(followSets(G)),
UnorderedElementsAre(
Pair(id("_"), UnorderedElementsAre(id("EOF"))),
Pair(id("decl-specifier-seq"), UnorderedElementsAre(id("EOF"))),

View File

@ -24,16 +24,16 @@ using Action = LRTable::Action;
TEST(LRTable, Builder) {
std::vector<std::string> GrammarDiags;
auto G = Grammar::parseBNF(R"bnf(
Grammar G = Grammar::parseBNF(R"bnf(
_ := expr # rule 0
expr := term # rule 1
expr := expr + term # rule 2
term := IDENTIFIER # rule 3
)bnf",
GrammarDiags);
GrammarDiags);
EXPECT_THAT(GrammarDiags, testing::IsEmpty());
SymbolID Term = *G->findNonterminal("term");
SymbolID Term = *G.findNonterminal("term");
SymbolID Eof = tokenSymbol(tok::eof);
SymbolID Identifier = tokenSymbol(tok::identifier);
SymbolID Plus = tokenSymbol(tok::plus);
@ -53,7 +53,7 @@ TEST(LRTable, Builder) {
{/*State=*/1, /*Rule=*/2},
{/*State=*/2, /*Rule=*/1},
};
LRTable T = LRTable::buildForTests(*G, Entries, ReduceEntries);
LRTable T = LRTable::buildForTests(G, Entries, ReduceEntries);
EXPECT_EQ(T.getShiftState(0, Eof), llvm::None);
EXPECT_THAT(T.getShiftState(0, Identifier), ValueIs(0));
EXPECT_THAT(T.getReduceRules(0), ElementsAre(0));