Eliminate duplicates when constructing choice rules

This commit is contained in:
Max Brunsfeld 2014-08-20 22:53:52 -07:00
parent fcdcdca303
commit 2963b08f79
2 changed files with 72 additions and 2 deletions

View 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

View file

@ -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 {