#include "test_helper.h" #include "helpers/stream_methods.h" #include "compiler/syntax_grammar.h" #include "compiler/lexical_grammar.h" #include "compiler/build_tables/parse_item_set_builder.h" #include "compiler/build_tables/lookahead_set.h" using namespace build_tables; using namespace rules; START_TEST describe("ParseItemSetBuilder", []() { vector lexical_variables; for (size_t i = 0; i < 20; i++) { lexical_variables.push_back({ "token_" + to_string(i), VariableTypeNamed, Blank{}, false }); } LexicalGrammar lexical_grammar{lexical_variables, {}}; it("adds items at the beginnings of referenced rules", [&]() { SyntaxGrammar grammar; grammar.variables = { SyntaxVariable{"rule0", VariableTypeNamed, { Production({ {Symbol::non_terminal(1), 0, AssociativityNone, Alias{}}, {Symbol::terminal(11), 0, AssociativityNone, Alias{}}, }, 0), }}, SyntaxVariable{"rule1", VariableTypeNamed, { Production({ {Symbol::terminal(12), 0, AssociativityNone, Alias{}}, {Symbol::terminal(13), 0, AssociativityNone, Alias{}}, }, 0), Production({ {Symbol::non_terminal(2), 0, AssociativityNone, Alias{}}, }, 0) }}, SyntaxVariable{"rule2", VariableTypeNamed, { Production({ {Symbol::terminal(14), 0, AssociativityNone, Alias{}}, {Symbol::terminal(15), 0, AssociativityNone, Alias{}}, }, 0) }}, }; auto production = [&](int variable_index, int production_index) -> const Production & { return grammar.variables[variable_index].productions[production_index]; }; ParseItemSet item_set{{ { ParseItem(rules::START(), production(0, 0), 0), LookaheadSet({ Symbol::terminal(10) }), } }}; ParseItemSetBuilder item_set_builder(grammar, lexical_grammar); item_set_builder.apply_transitive_closure(&item_set); AssertThat(item_set, Equals(ParseItemSet{{ { ParseItem(rules::START(), production(0, 0), 0), LookaheadSet({ Symbol::terminal(10) }) }, { ParseItem(Symbol::non_terminal(1), production(1, 0), 0), LookaheadSet({ Symbol::terminal(11) }) }, { ParseItem(Symbol::non_terminal(1), production(1, 1), 0), LookaheadSet({ Symbol::terminal(11) }) }, { ParseItem(Symbol::non_terminal(2), production(2, 0), 0), LookaheadSet({ Symbol::terminal(11) }) }, }})); }); it("handles rules with empty productions", [&]() { SyntaxGrammar grammar; grammar.variables = { SyntaxVariable{"rule0", VariableTypeNamed, { Production({ {Symbol::non_terminal(1), 0, AssociativityNone, Alias{}}, {Symbol::terminal(11), 0, AssociativityNone, Alias{}}, }, 0), }}, SyntaxVariable{"rule1", VariableTypeNamed, { Production({ {Symbol::terminal(12), 0, AssociativityNone, Alias{}}, {Symbol::terminal(13), 0, AssociativityNone, Alias{}}, }, 0), Production{{}, 0} }}, }; auto production = [&](int variable_index, int production_index) -> const Production & { return grammar.variables[variable_index].productions[production_index]; }; ParseItemSet item_set{{ { ParseItem(rules::START(), production(0, 0), 0), LookaheadSet({ Symbol::terminal(10) }), } }}; ParseItemSetBuilder item_set_builder(grammar, lexical_grammar); item_set_builder.apply_transitive_closure(&item_set); AssertThat(item_set, Equals(ParseItemSet{{ { ParseItem(rules::START(), production(0, 0), 0), LookaheadSet({ Symbol::terminal(10) }) }, { ParseItem(Symbol::non_terminal(1), production(1, 0), 0), LookaheadSet({ Symbol::terminal(11) }) }, { ParseItem(Symbol::non_terminal(1), production(1, 1), 0), LookaheadSet({ Symbol::terminal(11) }) }, }})); }); }); END_TEST