Fix item-set-closure bug w/ empty productions
This commit is contained in:
parent
216ce8c80b
commit
8725e96a65
7 changed files with 5600 additions and 5576 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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") }),
|
||||
|
|
|
|||
3238
spec/fixtures/parsers/cpp.c
vendored
3238
spec/fixtures/parsers/cpp.c
vendored
File diff suppressed because it is too large
Load diff
7811
spec/fixtures/parsers/javascript.c
vendored
7811
spec/fixtures/parsers/javascript.c
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue