Eliminate duplicates when constructing choice rules
This commit is contained in:
parent
fcdcdca303
commit
2963b08f79
2 changed files with 72 additions and 2 deletions
51
spec/compiler/rules/choice_spec.cc
Normal file
51
spec/compiler/rules/choice_spec.cc
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include "compiler/compiler_spec_helper.h"
|
||||
#include "compiler/rules/choice.h"
|
||||
|
||||
using namespace rules;
|
||||
|
||||
START_TEST
|
||||
|
||||
describe("Choice", []() {
|
||||
describe("constructing choices", [&]() {
|
||||
it("eliminates duplicate members", [&]() {
|
||||
auto rule = Choice::Build({
|
||||
seq({ sym("one"), sym("two") }),
|
||||
sym("three"),
|
||||
seq({ sym("one"), sym("two") })
|
||||
});
|
||||
|
||||
AssertThat(rule, EqualsPointer(choice({
|
||||
seq({ sym("one"), sym("two") }),
|
||||
sym("three"),
|
||||
})));
|
||||
});
|
||||
|
||||
it("eliminates duplicates within nested choices", [&]() {
|
||||
auto rule = Choice::Build({
|
||||
seq({ sym("one"), sym("two") }),
|
||||
Choice::Build({
|
||||
sym("three"),
|
||||
seq({ sym("one"), sym("two") })
|
||||
})
|
||||
});
|
||||
|
||||
AssertThat(rule, EqualsPointer(choice({
|
||||
seq({ sym("one"), sym("two") }),
|
||||
sym("three"),
|
||||
})));
|
||||
});
|
||||
|
||||
it("doesn't construct a choice if there's only one unique member", [&]() {
|
||||
auto rule = Choice::Build({
|
||||
sym("one"),
|
||||
Choice::Build({
|
||||
sym("one"),
|
||||
})
|
||||
});
|
||||
|
||||
AssertThat(rule, EqualsPointer(sym("one")));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
END_TEST
|
||||
|
|
@ -14,8 +14,27 @@ using std::dynamic_pointer_cast;
|
|||
|
||||
Choice::Choice(const vector<rule_ptr> &elements) : elements(elements) {}
|
||||
|
||||
rule_ptr Choice::Build(const vector<rule_ptr> &elements) {
|
||||
return make_shared<Choice>(elements);
|
||||
void add_choice_element(vector<rule_ptr> *vec, const rule_ptr new_rule) {
|
||||
auto choice = dynamic_pointer_cast<const Choice>(new_rule);
|
||||
if (choice.get()) {
|
||||
for (auto &child : choice->elements)
|
||||
add_choice_element(vec, child);
|
||||
} else {
|
||||
for (auto &el : *vec)
|
||||
if (el->operator==(*new_rule))
|
||||
return;
|
||||
vec->push_back(new_rule);
|
||||
}
|
||||
}
|
||||
|
||||
rule_ptr Choice::Build(const vector<rule_ptr> &inputs) {
|
||||
vector<rule_ptr> elements;
|
||||
for (auto &el : inputs)
|
||||
add_choice_element(&elements, el);
|
||||
if (elements.size() == 1)
|
||||
return elements.front();
|
||||
else
|
||||
return make_shared<Choice>(elements);
|
||||
}
|
||||
|
||||
bool Choice::operator==(const Rule &rule) const {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue