Fix item-set-closure bug w/ empty productions

This commit is contained in:
Max Brunsfeld 2015-10-15 23:59:47 -07:00
parent 216ce8c80b
commit 8725e96a65
7 changed files with 5600 additions and 5576 deletions

View file

@ -10,31 +10,31 @@ using namespace rules;
START_TEST
describe("item_set_closure", []() {
SyntaxGrammar grammar{{
SyntaxVariable("rule0", VariableTypeNamed, {
Production({
{Symbol(1), 0, AssociativityNone, 100},
{Symbol(11, true), 0, AssociativityNone, 101},
}),
}),
SyntaxVariable("rule1", VariableTypeNamed, {
Production({
{Symbol(12, true), 0, AssociativityNone, 102},
{Symbol(13, true), 0, AssociativityNone, 103},
}),
Production({
{Symbol(2), 0, AssociativityNone, 104},
})
}),
SyntaxVariable("rule2", VariableTypeNamed, {
Production({
{Symbol(14, true), 0, AssociativityNone, 105},
{Symbol(15, true), 0, AssociativityNone, 106},
})
}),
}, {}, {}};
it("adds items at the beginnings of referenced rules", [&]() {
SyntaxGrammar grammar{{
SyntaxVariable("rule0", VariableTypeNamed, {
Production({
{Symbol(1), 0, AssociativityNone, 100},
{Symbol(11, true), 0, AssociativityNone, 101},
}),
}),
SyntaxVariable("rule1", VariableTypeNamed, {
Production({
{Symbol(12, true), 0, AssociativityNone, 102},
{Symbol(13, true), 0, AssociativityNone, 103},
}),
Production({
{Symbol(2), 0, AssociativityNone, 104},
})
}),
SyntaxVariable("rule2", VariableTypeNamed, {
Production({
{Symbol(14, true), 0, AssociativityNone, 105},
{Symbol(15, true), 0, AssociativityNone, 106},
})
}),
}, {}, {}};
ParseItemSet item_set = item_set_closure(ParseItemSet({
{
ParseItem(Symbol(0), 0, 0, 100),
@ -61,6 +61,46 @@ describe("item_set_closure", []() {
},
})));
});
it("handles rules with empty productions", [&]() {
SyntaxGrammar grammar{{
SyntaxVariable("rule0", VariableTypeNamed, {
Production({
{Symbol(1), 0, AssociativityNone, 100},
{Symbol(11, true), 0, AssociativityNone, 101},
}),
}),
SyntaxVariable("rule1", VariableTypeNamed, {
Production({
{Symbol(12, true), 0, AssociativityNone, 102},
{Symbol(13, true), 0, AssociativityNone, 103},
}),
Production({})
}),
}, {}, {}};
ParseItemSet item_set = item_set_closure(ParseItemSet({
{
ParseItem(Symbol(0), 0, 0, 100),
LookaheadSet({ Symbol(10, true) }),
}
}), grammar);
AssertThat(item_set, Equals(ParseItemSet({
{
ParseItem(Symbol(0), 0, 0, 100),
LookaheadSet({ Symbol(10, true) })
},
{
ParseItem(Symbol(1), 0, 0, 102),
LookaheadSet({ Symbol(11, true) })
},
{
ParseItem(Symbol(1), 1, 0, 0),
LookaheadSet({ Symbol(11, true) })
},
})));
});
});
END_TEST

View file

@ -17,6 +17,18 @@ describe("Compile", []() {
AssertThat(error, Equals<const GrammarError *>(nullptr));
});
});
describe("when the grammar's start symbol is blank", [&]() {
it("does not fail", [&]() {
Grammar grammar({
{ "rule1", blank() }
});
auto result = compile(grammar, "test_grammar");
const GrammarError *error = result.second;
AssertThat(error, Equals<const GrammarError *>(nullptr));
});
});
});
END_TEST

View file

@ -61,6 +61,12 @@ describe("extract_choices", []() {
})));
});
it("handles blank rules", [&]() {
AssertThat(extract_choices(blank()), Equals(rule_vector({
blank(),
})));
});
it("does not move choices outside of repeats", [&]() {
auto rule = seq({
choice({ sym("a"), sym("b") }),

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -112,13 +112,18 @@ class ParseTableBuilder {
};
CompletionStatus get_completion_status(const ParseItem &item) {
CompletionStatus result = { false, 0, rules::AssociativityNone };
const Production &production =
grammar.productions(item.lhs())[item.production_index];
if (item.step_index == production.size()) {
const ProductionStep &last_step = production[item.step_index - 1];
return { true, last_step.precedence, last_step.associativity };
result.is_done = true;
if (item.step_index > 0) {
const ProductionStep &last_step = production[item.step_index - 1];
result.precedence = last_step.precedence;
result.associativity = last_step.associativity;
}
}
return { false, 0, rules::AssociativityNone };
return result;
}
void add_reduce_actions(const ParseItemSet &item_set, ParseStateId state_id) {

View file

@ -72,11 +72,11 @@ ParseItemSet item_set_closure(const ParseItemSet &input_item_set,
// Add each of the next symbol's productions to be processed recursively.
size_t i = 0;
for (const Production &production : grammar.productions(next_symbol)) {
if (!production.empty())
items_to_process.push_back({
ParseItem(next_symbol, i, 0, production[0].rule_id),
next_lookahead_symbols,
});
int rule_id = production.empty() ? 0 : production[0].rule_id;
items_to_process.push_back({
ParseItem(next_symbol, i, 0, rule_id),
next_lookahead_symbols,
});
i++;
}
}