forked from OSchip/llvm-project
[pseudo] Grammar::parseBNF returns Grammar not unique_ptr. NFC
This commit is contained in:
parent
313f9cd81d
commit
3f028c02ba
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; };
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"))),
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue